Compare commits
43 Commits
web-improv
...
v0.22-alph
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
4c049ac349 | ||
|
|
fca3f52424 | ||
|
|
27c0f23ffa | ||
|
|
d6590e9a8d | ||
|
|
c93beec30d | ||
|
|
47628ba4af | ||
|
|
98e43aba49 | ||
|
|
404b42c9f9 | ||
|
|
6b831359dc | ||
|
|
10076e35f4 | ||
|
|
76a6a58a42 | ||
|
|
62069ab80a | ||
|
|
e1643a681a | ||
|
|
6f30613ce0 | ||
|
|
d539753e72 | ||
|
|
cc80f2b4c1 | ||
|
|
1893f0528b | ||
|
|
ce1f1d9db5 | ||
|
|
8b42fcfda3 | ||
|
|
60b9d1d61d | ||
|
|
61ae5d0537 | ||
|
|
7ffcbde82e | ||
|
|
ccc53f1cfb | ||
|
|
be2b447b46 | ||
|
|
b333dd8708 | ||
|
|
4b5524e467 | ||
|
|
5b970d5197 | ||
|
|
617ae0dcdd | ||
|
|
a1d2ae9a23 | ||
|
|
9372386f6b | ||
|
|
4b97f9d4af | ||
|
|
6af1fd2837 | ||
|
|
b7545830ba | ||
|
|
4796c4acb7 | ||
|
|
de3fb77db2 | ||
|
|
036d3dccd6 | ||
|
|
24cfc54c06 | ||
|
|
173c8cbe3a | ||
|
|
2d8cd0e0ab | ||
|
|
ee667257ef | ||
|
|
3c4f57cbe7 | ||
|
|
3ee598004a | ||
|
|
673cabe7ab |
@@ -21,8 +21,8 @@
|
|||||||
"ROS",
|
"ROS",
|
||||||
"ROS Kinetic",
|
"ROS Kinetic",
|
||||||
"ROS Melodic",
|
"ROS Melodic",
|
||||||
|
"ROS Noetic",
|
||||||
"OpenCV",
|
"OpenCV",
|
||||||
"OpenVPN",
|
|
||||||
"Gazebo",
|
"Gazebo",
|
||||||
"GitHub",
|
"GitHub",
|
||||||
"FPV",
|
"FPV",
|
||||||
@@ -107,9 +107,7 @@
|
|||||||
"UDP",
|
"UDP",
|
||||||
"QR",
|
"QR",
|
||||||
"Li-ion",
|
"Li-ion",
|
||||||
"Nvidia",
|
"Nvidia"
|
||||||
"VirtualBox",
|
|
||||||
"VMware"
|
|
||||||
],
|
],
|
||||||
"code_blocks": false
|
"code_blocks": false
|
||||||
},
|
},
|
||||||
|
|||||||
23
.travis.yml
@@ -5,12 +5,12 @@ services:
|
|||||||
- docker
|
- docker
|
||||||
env:
|
env:
|
||||||
global:
|
global:
|
||||||
- DOCKER="sfalexrog/img-tool:qemu-update"
|
- DOCKER="sfalexrog/img-tool:qemu-aarch64"
|
||||||
- TARGET_REPO="https://github.com/${TRAVIS_REPO_SLUG}.git"
|
- TARGET_REPO="https://github.com/${TRAVIS_REPO_SLUG}.git"
|
||||||
- IMAGE_VERSION=${TRAVIS_TAG:-${TRAVIS_COMMIT:0:7}}
|
- IMAGE_VERSION=${TRAVIS_TAG:-${TRAVIS_COMMIT:0:7}}
|
||||||
- IMAGE_NAME="$(basename -s '.git' ${TARGET_REPO})_${IMAGE_VERSION}.img"
|
- IMAGE_NAME="$(basename -s '.git' ${TARGET_REPO})_${IMAGE_VERSION}.img"
|
||||||
git:
|
git:
|
||||||
depth: 1
|
depth: 50
|
||||||
jobs:
|
jobs:
|
||||||
fast_finish: true
|
fast_finish: true
|
||||||
include:
|
include:
|
||||||
@@ -38,7 +38,7 @@ jobs:
|
|||||||
- cp images/*.zip imgcache
|
- cp images/*.zip imgcache
|
||||||
after_success:
|
after_success:
|
||||||
- sudo chmod -R 777 *
|
- sudo chmod -R 777 *
|
||||||
- cd images && zip -9 ${IMAGE_NAME}.zip ${IMAGE_NAME} && stat --printf="Compressed image size:%s\n" ${IMAGE_NAME}.zip
|
- cd images && zip ${IMAGE_NAME}.zip ${IMAGE_NAME} && stat --printf="Compressed image size:%s\n" ${IMAGE_NAME}.zip
|
||||||
before_deploy:
|
before_deploy:
|
||||||
# Set up git user name and tag this commit
|
# Set up git user name and tag this commit
|
||||||
- git config --local user.name "goldarte"
|
- git config --local user.name "goldarte"
|
||||||
@@ -68,6 +68,14 @@ jobs:
|
|||||||
- docker pull ${NATIVE_DOCKER}
|
- docker pull ${NATIVE_DOCKER}
|
||||||
script:
|
script:
|
||||||
- docker run --rm -v $(pwd):/root/catkin_ws/src/clover ${NATIVE_DOCKER} /root/catkin_ws/src/clover/builder/standalone-install.sh
|
- docker run --rm -v $(pwd):/root/catkin_ws/src/clover ${NATIVE_DOCKER} /root/catkin_ws/src/clover/builder/standalone-install.sh
|
||||||
|
- stage: Build
|
||||||
|
name: "Native Noetic build"
|
||||||
|
env:
|
||||||
|
- NATIVE_DOCKER=ros:noetic-ros-base
|
||||||
|
before_script:
|
||||||
|
- docker pull ${NATIVE_DOCKER}
|
||||||
|
script:
|
||||||
|
- docker run --rm -v $(pwd):/root/catkin_ws/src/clover ${NATIVE_DOCKER} /root/catkin_ws/src/clover/builder/standalone-install.sh
|
||||||
- stage: Build
|
- stage: Build
|
||||||
name: "Documentation"
|
name: "Documentation"
|
||||||
language: node_js
|
language: node_js
|
||||||
@@ -77,7 +85,6 @@ jobs:
|
|||||||
- sudo sh -c "echo ttf-mscorefonts-installer msttcorefonts/accepted-mscorefonts-eula select true | debconf-set-selections"
|
- sudo sh -c "echo ttf-mscorefonts-installer msttcorefonts/accepted-mscorefonts-eula select true | debconf-set-selections"
|
||||||
- sudo apt update && sudo apt install -y calibre msttcorefonts
|
- sudo apt update && sudo apt install -y calibre msttcorefonts
|
||||||
- npm install gitbook-cli -g
|
- npm install gitbook-cli -g
|
||||||
- gitbook fetch 3.2.3 && npm i npm@3.10.10 --prefix=~/.gitbook/versions/3.2.3/ # fixing https://travis-ci.org/github/CopterExpress/clover/jobs/766541125#L932
|
|
||||||
- npm install markdownlint-cli -g
|
- npm install markdownlint-cli -g
|
||||||
- npm install svgexport -g
|
- npm install svgexport -g
|
||||||
- gitbook -V
|
- gitbook -V
|
||||||
@@ -88,13 +95,7 @@ jobs:
|
|||||||
- ./check_unused_assets.py
|
- ./check_unused_assets.py
|
||||||
- gitbook install
|
- gitbook install
|
||||||
- gitbook build
|
- gitbook build
|
||||||
- for i in 1 2 3 4; do gitbook pdf ./ _book/clover.pdf && break || sleep 1; done
|
- gitbook pdf ./ _book/clover.pdf
|
||||||
- sudo apt-get install ghostscript
|
|
||||||
- gs -sDEVICE=pdfwrite -dCompatibilityLevel=1.4 -dPDFSETTINGS=/default -dNOPAUSE -dQUIET -dBATCH -dDetectDuplicateImages -dCompressFonts=true -r150 -sOutputFile=_book/clover_ru_compressed.pdf _book/clover_ru.pdf
|
|
||||||
- gs -sDEVICE=pdfwrite -dCompatibilityLevel=1.4 -dPDFSETTINGS=/default -dNOPAUSE -dQUIET -dBATCH -dDetectDuplicateImages -dCompressFonts=true -r150 -sOutputFile=_book/clover_en_compressed.pdf _book/clover_en.pdf
|
|
||||||
- rm _book/clover_ru.pdf && mv _book/clover_ru_compressed.pdf _book/clover_ru.pdf
|
|
||||||
- rm _book/clover_en.pdf && mv _book/clover_en_compressed.pdf _book/clover_en.pdf
|
|
||||||
- ls -lah _book/clover*.pdf
|
|
||||||
deploy:
|
deploy:
|
||||||
provider: pages
|
provider: pages
|
||||||
local_dir: _book
|
local_dir: _book
|
||||||
|
|||||||
15
README.md
@@ -1,14 +1,12 @@
|
|||||||
# clover🍀: create autonomous drones easily
|
# COEX Clover Drone Kit
|
||||||
|
|
||||||
<img src="docs/assets/clover42-main.png" align="right" width="400px" alt="COEX Clover Drone">
|
<img src="docs/assets/clever4-front-white.png" align="right" width="400px" alt="Clover Drone">
|
||||||
|
|
||||||
Clover is an open source [ROS](https://www.ros.org)-based framework, providing user-friendly tools to control [PX4](https://px4.io)-powered drones. Clover is available as a ROS package, but is shipped mainly as a preconfigured image for Raspberry Pi. Once you've installed Raspberry Pi on your drone and flashed the image to its microSD card, taking the drone up in the air is a matter of minutes.
|
Clover is an educational programmable drone kit consisting of an unassembled quadcopter, open source software and documentation. The kit includes Pixracer-compatible autopilot running PX4 firmware, Raspberry Pi 4 as companion computer, a camera for computer vision navigation as well as additional sensors and peripheral devices.
|
||||||
|
|
||||||
COEX Clover Drone is an educational programmable drone kit, suited perfectly for running clover software. The kit is shipped unassembled and includes Pixracer-compatible autopilot running PX4 firmware, Raspberry Pi 4 as a companion computer, a camera for computer vision navigation as well as additional sensors and peripheral devices. Batteries included.
|
The main documentation is available [on Gitbook](https://clover.coex.tech/).
|
||||||
|
|
||||||
The main documentation is available at [https://clover.coex.tech](https://clover.coex.tech/). Official website: [coex.tech/clover](https://coex.tech/clover).
|
Official website: <a href="https://coex.tech/clover">coex.tech/clover</a>.
|
||||||
|
|
||||||
[__Support us on Kickstarter!__](https://www.kickstarter.com/projects/copterexpress/cloverdrone)
|
|
||||||
|
|
||||||
## Video compilation
|
## Video compilation
|
||||||
|
|
||||||
@@ -21,12 +19,11 @@ Clover drone is used on a wide range of educational events, including [Copter Ha
|
|||||||
Preconfigured image for Raspberry Pi with installed and configured software, ready to fly, is available [in the Releases section](https://github.com/CopterExpress/clover/releases).
|
Preconfigured image for Raspberry Pi with installed and configured software, ready to fly, is available [in the Releases section](https://github.com/CopterExpress/clover/releases).
|
||||||
|
|
||||||
[](https://travis-ci.org/CopterExpress/clover)
|
[](https://travis-ci.org/CopterExpress/clover)
|
||||||

|
|
||||||
|
|
||||||
Image features:
|
Image features:
|
||||||
|
|
||||||
* Raspbian Buster
|
* Raspbian Buster
|
||||||
* [ROS Melodic](http://wiki.ros.org/melodic)
|
* [ROS Noetic](http://wiki.ros.org/noetic)
|
||||||
* Configured networking
|
* Configured networking
|
||||||
* OpenCV
|
* OpenCV
|
||||||
* [`mavros`](http://wiki.ros.org/mavros)
|
* [`mavros`](http://wiki.ros.org/mavros)
|
||||||
|
|||||||
@@ -1,8 +0,0 @@
|
|||||||
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
|
||||||
Changelog for package aruco_pose
|
|
||||||
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
|
||||||
|
|
||||||
0.21.1 (2020-11-17)
|
|
||||||
-------------------
|
|
||||||
* First release of aruco_pose package to ROS
|
|
||||||
* Contributors: Alamoris, Alexey Rogachevskiy, Arthur Golubtsov, Ilya Petrov, Oleg Kalachev
|
|
||||||
@@ -22,13 +22,21 @@ find_package(catkin REQUIRED COMPONENTS
|
|||||||
dynamic_reconfigure
|
dynamic_reconfigure
|
||||||
)
|
)
|
||||||
|
|
||||||
find_package(OpenCV 3 REQUIRED COMPONENTS core imgproc calib3d)
|
# Workaround for OpenCV 3/4 support
|
||||||
|
set(_opencv_version 4)
|
||||||
|
find_package(OpenCV ${_opencv_version} QUIET)
|
||||||
|
if (NOT OpenCV_FOUND)
|
||||||
|
message(STATUS "Did not find OpenCV 4, searching for OpenCV 3")
|
||||||
|
set(_opencv_version 3)
|
||||||
|
endif()
|
||||||
|
|
||||||
|
find_package(OpenCV ${_opencv_version} REQUIRED COMPONENTS core imgproc calib3d)
|
||||||
if ("${OpenCV_VERSION_MINOR}" LESS "9")
|
if ("${OpenCV_VERSION_MINOR}" LESS "9")
|
||||||
message(STATUS "OpenCV version too low, using vendored ArUco package")
|
message(STATUS "OpenCV version too low, using vendored ArUco package")
|
||||||
include(vendor/VendorOpenCV.cmake)
|
include(vendor/VendorOpenCV.cmake)
|
||||||
else()
|
else()
|
||||||
message(STATUS "Using system OpenCV ArUco package")
|
message(STATUS "Using system OpenCV ArUco package")
|
||||||
find_package(OpenCV 3 REQUIRED COMPONENTS aruco)
|
find_package(OpenCV ${_opencv_version} REQUIRED COMPONENTS aruco)
|
||||||
endif()
|
endif()
|
||||||
message(STATUS "OpenCV include dirs: ${OpenCV_INCLUDE_DIRS}")
|
message(STATUS "OpenCV include dirs: ${OpenCV_INCLUDE_DIRS}")
|
||||||
message(STATUS "OpenCV libraries: ${OpenCV_LIBRARIES}")
|
message(STATUS "OpenCV libraries: ${OpenCV_LIBRARIES}")
|
||||||
@@ -111,7 +119,7 @@ generate_messages(
|
|||||||
|
|
||||||
## Generate dynamic reconfigure parameters in the 'cfg' folder
|
## Generate dynamic reconfigure parameters in the 'cfg' folder
|
||||||
generate_dynamic_reconfigure_options(
|
generate_dynamic_reconfigure_options(
|
||||||
cfg/Detector.cfg
|
cfg/DetectorParams.cfg
|
||||||
)
|
)
|
||||||
|
|
||||||
###################################
|
###################################
|
||||||
@@ -207,6 +215,10 @@ target_link_libraries(aruco_pose
|
|||||||
# DESTINATION ${CATKIN_PACKAGE_SHARE_DESTINATION}
|
# DESTINATION ${CATKIN_PACKAGE_SHARE_DESTINATION}
|
||||||
# )
|
# )
|
||||||
|
|
||||||
|
catkin_install_python(PROGRAMS src/genmap.py
|
||||||
|
DESTINATION ${CATKIN_PACKAGE_BIN_DESTINATION}
|
||||||
|
)
|
||||||
|
|
||||||
#############
|
#############
|
||||||
## Testing ##
|
## Testing ##
|
||||||
#############
|
#############
|
||||||
|
|||||||
@@ -8,8 +8,6 @@ p = cv2.aruco.DetectorParameters_create()
|
|||||||
|
|
||||||
gen = ParameterGenerator()
|
gen = ParameterGenerator()
|
||||||
|
|
||||||
gen.add("enabled", bool_t, 0, "if detection enabled", True)
|
|
||||||
|
|
||||||
gen.add("adaptiveThreshConstant", double_t, 0,
|
gen.add("adaptiveThreshConstant", double_t, 0,
|
||||||
"Constant for adaptive thresholding before finding contours",
|
"Constant for adaptive thresholding before finding contours",
|
||||||
p.adaptiveThreshConstant, 0, 100)
|
p.adaptiveThreshConstant, 0, 100)
|
||||||
@@ -1,7 +1,7 @@
|
|||||||
<?xml version="1.0"?>
|
<?xml version="1.0"?>
|
||||||
<package format="2">
|
<package format="2">
|
||||||
<name>aruco_pose</name>
|
<name>aruco_pose</name>
|
||||||
<version>0.21.1</version>
|
<version>0.0.1</version>
|
||||||
<description>Positioning with ArUco markers</description>
|
<description>Positioning with ArUco markers</description>
|
||||||
|
|
||||||
<maintainer email="okalachev@gmail.com">Oleg Kalachev</maintainer>
|
<maintainer email="okalachev@gmail.com">Oleg Kalachev</maintainer>
|
||||||
|
|||||||
@@ -62,7 +62,6 @@ private:
|
|||||||
std::unique_ptr<tf2_ros::Buffer> tf_buffer_;
|
std::unique_ptr<tf2_ros::Buffer> tf_buffer_;
|
||||||
std::unique_ptr<tf2_ros::TransformListener> tf_listener_;
|
std::unique_ptr<tf2_ros::TransformListener> tf_listener_;
|
||||||
std::shared_ptr<dynamic_reconfigure::Server<aruco_pose::DetectorConfig>> dyn_srv_;
|
std::shared_ptr<dynamic_reconfigure::Server<aruco_pose::DetectorConfig>> dyn_srv_;
|
||||||
bool enabled_ = true;
|
|
||||||
cv::Ptr<cv::aruco::Dictionary> dictionary_;
|
cv::Ptr<cv::aruco::Dictionary> dictionary_;
|
||||||
cv::Ptr<cv::aruco::DetectorParameters> parameters_;
|
cv::Ptr<cv::aruco::DetectorParameters> parameters_;
|
||||||
image_transport::Publisher debug_pub_;
|
image_transport::Publisher debug_pub_;
|
||||||
@@ -129,8 +128,6 @@ public:
|
|||||||
private:
|
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;
|
|
||||||
|
|
||||||
Mat image = cv_bridge::toCvShare(msg, "bgr8")->image;
|
Mat image = cv_bridge::toCvShare(msg, "bgr8")->image;
|
||||||
|
|
||||||
vector<int> ids;
|
vector<int> ids;
|
||||||
@@ -359,7 +356,6 @@ private:
|
|||||||
|
|
||||||
void paramCallback(aruco_pose::DetectorConfig &config, uint32_t level)
|
void paramCallback(aruco_pose::DetectorConfig &config, uint32_t level)
|
||||||
{
|
{
|
||||||
enabled_ = config.enabled;
|
|
||||||
parameters_->adaptiveThreshConstant = config.adaptiveThreshConstant;
|
parameters_->adaptiveThreshConstant = config.adaptiveThreshConstant;
|
||||||
parameters_->adaptiveThreshWinSizeMin = config.adaptiveThreshWinSizeMin;
|
parameters_->adaptiveThreshWinSizeMin = config.adaptiveThreshWinSizeMin;
|
||||||
parameters_->adaptiveThreshWinSizeMax = config.adaptiveThreshWinSizeMax;
|
parameters_->adaptiveThreshWinSizeMax = config.adaptiveThreshWinSizeMax;
|
||||||
|
|||||||
@@ -3,26 +3,11 @@
|
|||||||
|
|
||||||
#include "draw.h"
|
#include "draw.h"
|
||||||
#include <math.h>
|
#include <math.h>
|
||||||
|
#include <vector>
|
||||||
|
|
||||||
using namespace cv;
|
using namespace cv;
|
||||||
using namespace cv::aruco;
|
using namespace cv::aruco;
|
||||||
|
|
||||||
static void _cvProjectPoints2( const CvMat* object_points, const CvMat* rotation_vector,
|
|
||||||
const CvMat* translation_vector, const CvMat* camera_matrix,
|
|
||||||
const CvMat* distortion_coeffs, CvMat* image_points,
|
|
||||||
CvMat* dpdrot CV_DEFAULT(NULL), CvMat* dpdt CV_DEFAULT(NULL),
|
|
||||||
CvMat* dpdf CV_DEFAULT(NULL), CvMat* dpdc CV_DEFAULT(NULL),
|
|
||||||
CvMat* dpddist CV_DEFAULT(NULL),
|
|
||||||
double aspect_ratio CV_DEFAULT(0));
|
|
||||||
|
|
||||||
static void _projectPoints( InputArray objectPoints,
|
|
||||||
InputArray rvec, InputArray tvec,
|
|
||||||
InputArray cameraMatrix, InputArray distCoeffs,
|
|
||||||
OutputArray imagePoints,
|
|
||||||
OutputArray jacobian = noArray(),
|
|
||||||
double aspectRatio = 0 );
|
|
||||||
|
|
||||||
|
|
||||||
void _drawPlanarBoard(Board *_board, Size outSize, OutputArray _img, int marginSize,
|
void _drawPlanarBoard(Board *_board, Size outSize, OutputArray _img, int marginSize,
|
||||||
int borderBits, bool drawAxis) {
|
int borderBits, bool drawAxis) {
|
||||||
|
|
||||||
@@ -142,35 +127,194 @@ void _drawPlanarBoard(Board *_board, Size outSize, OutputArray _img, int marginS
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Draw a (potentially partially visible) line. */
|
/**
|
||||||
static void linePartial(InputOutputArray image, Point3f p1, Point3f p2, const Scalar& color,
|
* @brief Convert point coordinates from world space to camera space.
|
||||||
int thickness = 1, int lineType = LINE_8, int shift = 0)
|
*
|
||||||
|
* @param points A vector of points in world space.
|
||||||
|
* @param rvec Rotation matrix or Rodrigues rotation vector.
|
||||||
|
* @param tvec Translation vector from world to camera space.
|
||||||
|
*
|
||||||
|
* @return A vector of points in camera space.
|
||||||
|
*/
|
||||||
|
template<typename CvPointType>
|
||||||
|
static std::vector<CvPointType> worldToCamera(const std::vector<CvPointType>& points,
|
||||||
|
const cv::Mat& rvec, const cv::Mat& tvec)
|
||||||
{
|
{
|
||||||
// If both points are behind the screen, don't draw anything
|
// We operate with CV_64F matrices internally to avoid precision loss
|
||||||
if (p1.z <= 0 && p2.z <= 0) {
|
cv::Mat rvec_64f;
|
||||||
return;
|
cv::Mat tvec_64f;
|
||||||
|
rvec.convertTo(rvec_64f, CV_64F);
|
||||||
|
tvec.convertTo(tvec_64f, CV_64F);
|
||||||
|
|
||||||
|
// Convert Rodrigues vector to rotation matrix
|
||||||
|
cv::Mat rmat;
|
||||||
|
if ((rvec_64f.cols == 3 && rvec_64f.rows == 1) ||
|
||||||
|
(rvec_64f.cols == 1 && rvec_64f.rows == 3))
|
||||||
|
{
|
||||||
|
Rodrigues(rvec_64f, rmat);
|
||||||
}
|
}
|
||||||
Point2f p1p{p1.x, p1.y};
|
else
|
||||||
Point2f p2p{p2.x, p2.y};
|
{
|
||||||
// If points are on the different sides of the plane, compute intersection point
|
rmat = rvec_64f.clone();
|
||||||
if (p1.z * p2.z < 0) {
|
|
||||||
// Compute intersection point with the screen
|
|
||||||
// We denote alpha as such:
|
|
||||||
// xi = (1 - alpha) * x1 + alpha * x2
|
|
||||||
// yi = (1 - alpha) * y1 + alpha * y2
|
|
||||||
// zi = (1 - alpha) * z1 + alpha * z2 = 0
|
|
||||||
// Thus, alpha can be expressed as
|
|
||||||
// alpha = z1 / (z1 - z2)
|
|
||||||
float alpha = p1.z / (p1.z - p2.z);
|
|
||||||
Point2f pi{(1 - alpha) * p1.x + alpha * p2.x, (1 - alpha) * p1.y + alpha * p2.y};
|
|
||||||
// Now, if z1 is negative, we draw the line from (xi, yi) to (x2, y2), else we draw from (x1, y1) to (xi, yi)
|
|
||||||
if (p1.z < 0) {
|
|
||||||
p1p = pi;
|
|
||||||
} else {
|
|
||||||
p2p = pi;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
line(image, p1p, p2p, color, thickness, lineType, shift);
|
// Make sure tvec has a size of (3, 1)
|
||||||
|
if (tvec_64f.rows == 1)
|
||||||
|
{
|
||||||
|
tvec_64f = tvec_64f.t();
|
||||||
|
}
|
||||||
|
std::vector<CvPointType> result;
|
||||||
|
result.reserve(points.size());
|
||||||
|
for(const auto& point : points)
|
||||||
|
{
|
||||||
|
// Calculate point coordinates in camera frame
|
||||||
|
// static_casts are here to silence potential narrowing conversion warnings
|
||||||
|
CvPointType camPoint{
|
||||||
|
static_cast<decltype(CvPointType::x)>(point.x * rmat.at<double>(0,0) + point.y * rmat.at<double>(0,1) + point.z * rmat.at<double>(0,2) + tvec_64f.at<double>(0)),
|
||||||
|
static_cast<decltype(CvPointType::y)>(point.x * rmat.at<double>(1,0) + point.y * rmat.at<double>(1,1) + point.z * rmat.at<double>(1,2) + tvec_64f.at<double>(1)),
|
||||||
|
static_cast<decltype(CvPointType::z)>(point.x * rmat.at<double>(2,0) + point.y * rmat.at<double>(2,1) + point.z * rmat.at<double>(2,2) + tvec_64f.at<double>(2))
|
||||||
|
};
|
||||||
|
result.push_back(camPoint);
|
||||||
|
}
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Project points from camera space to screen space, applying distortion in the process.
|
||||||
|
*
|
||||||
|
* @param points A vector of points in camera space.
|
||||||
|
* @param cameraMatrix OpenCV intrinsic camera matrix.
|
||||||
|
* @param distCoeffs OpenCV distortion model coefficients.
|
||||||
|
*
|
||||||
|
* @return A vector of points in screen space.
|
||||||
|
*/
|
||||||
|
template<typename CvPointType>
|
||||||
|
static std::vector<CvPointType> cameraToScreen(const std::vector<CvPointType>& points,
|
||||||
|
const cv::Mat& cameraMatrix,
|
||||||
|
const cv::Mat& distCoeffs)
|
||||||
|
{
|
||||||
|
// We operate with CV_64F matrices internally to avoid precision loss
|
||||||
|
cv::Mat cm_64f; // camera matrix, CV_64F
|
||||||
|
cv::Mat dc_64f; // distortion coefficients, CV_64F
|
||||||
|
cameraMatrix.convertTo(cm_64f, CV_64F);
|
||||||
|
distCoeffs.convertTo(dc_64f, CV_64F);
|
||||||
|
|
||||||
|
// Make sure distortion vector has a size of (N, 1)
|
||||||
|
if (dc_64f.rows == 1)
|
||||||
|
{
|
||||||
|
dc_64f = dc_64f.t();
|
||||||
|
}
|
||||||
|
|
||||||
|
// We will always use 12 distortion coefficients,
|
||||||
|
// and we can safely pad missing ones with zeroes
|
||||||
|
dc_64f.resize(12, 0.0);
|
||||||
|
|
||||||
|
std::vector<CvPointType> result;
|
||||||
|
result.reserve(points.size());
|
||||||
|
|
||||||
|
for(const auto& point : points)
|
||||||
|
{
|
||||||
|
// Apply perspective projection, preserving initial Z coordinate
|
||||||
|
// Always use double-precision
|
||||||
|
cv::Point3d camPoint{
|
||||||
|
point.x / point.z,
|
||||||
|
point.y / point.z,
|
||||||
|
point.z
|
||||||
|
};
|
||||||
|
|
||||||
|
// Apply distortion
|
||||||
|
// Note that we do not consider tilted sensor distortion
|
||||||
|
// r^2 - distance from the image center squared
|
||||||
|
double r2 = camPoint.x * camPoint.x + camPoint.y * camPoint.y;
|
||||||
|
// r^4 - same, but to the 4th power
|
||||||
|
double r4 = r2 * r2;
|
||||||
|
// r^6 - same, but to the 6th power
|
||||||
|
double r6 = r4 * r2;
|
||||||
|
// tg1 - first tangential shift factor (2 * x * y)
|
||||||
|
double tg1 = 2 * camPoint.x * camPoint.y;
|
||||||
|
// tg2 - second tangential shift factor (r^2 + 2 * x^2)
|
||||||
|
double tg2 = r2 + 2 * camPoint.x * camPoint.x;
|
||||||
|
// tg3 - third tangential shift factor (r^2 + 2 * y^2)
|
||||||
|
double tg3 = r2 + 2 * camPoint.y * camPoint.y;
|
||||||
|
// polynomial distortion factor (numerator)
|
||||||
|
double pndist = 1 + dc_64f.at<double>(0) * r2 + dc_64f.at<double>(1) * r4 + dc_64f.at<double>(4) * r6;
|
||||||
|
// polynomial distortion factror (denominator)
|
||||||
|
double pddist = 1.0 / (1 + dc_64f.at<double>(5) * r2 + dc_64f.at<double>(6) * r4 + dc_64f.at<double>(7) * r6);
|
||||||
|
// Distorted point coordinates (always double-precision)
|
||||||
|
cv::Point3d distortedPoint{
|
||||||
|
camPoint.x * pndist * pddist + dc_64f.at<double>(2) * tg1 + dc_64f.at<double>(3) * tg2 + dc_64f.at<double>(8) * r2 + dc_64f.at<double>(9) * r4,
|
||||||
|
camPoint.y * pndist * pddist + dc_64f.at<double>(2) * tg3 + dc_64f.at<double>(3) * tg1 + dc_64f.at<double>(10) * r2 + dc_64f.at<double>(11) * r4,
|
||||||
|
camPoint.z
|
||||||
|
};
|
||||||
|
|
||||||
|
// Convert to screen space
|
||||||
|
// We use static_cast here to silence potential warnings about narrowing conversions
|
||||||
|
// (we expect that to be the case)
|
||||||
|
CvPointType screenPoint{
|
||||||
|
static_cast<decltype(CvPointType::x)>(distortedPoint.x * cm_64f.at<double>(0, 0) + cm_64f.at<double>(0, 2)),
|
||||||
|
static_cast<decltype(CvPointType::y)>(distortedPoint.y * cm_64f.at<double>(1, 1) + cm_64f.at<double>(1, 2)),
|
||||||
|
static_cast<decltype(CvPointType::z)>(distortedPoint.z)
|
||||||
|
};
|
||||||
|
|
||||||
|
result.push_back(screenPoint);
|
||||||
|
}
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Clip a line against a clip plane.
|
||||||
|
*
|
||||||
|
* This function "clips" a line (described by two points in *camera space*)
|
||||||
|
* against a clip plane that is `clipPlaneDistance` meters away from the
|
||||||
|
* camera focal point. If both points are further away from the focal point
|
||||||
|
* than `clipPlaneDistance`, they will be returned unmodified. If one of the
|
||||||
|
* points is behind the clipping plane, a point *on* the clipping plane will
|
||||||
|
* be computed and returned as one of the points.
|
||||||
|
*
|
||||||
|
* If none of the points are visible, an empty vector will be returned.
|
||||||
|
*
|
||||||
|
* @param p1 First point on the line, in camera space.
|
||||||
|
* @param p2 Second point on the line, in camera space.
|
||||||
|
* @param clipPlaneDistance Distance from the focal point to the clipping plane.
|
||||||
|
* @return A vector of zero or two points on the clipped line, in camera space.
|
||||||
|
*/
|
||||||
|
static std::vector<Point3f> lineClip(Point3f p1, Point3f p2, float clipPlaneDistance = 0.1f)
|
||||||
|
{
|
||||||
|
// We don't need to compute an intersection if both points are
|
||||||
|
// behind us
|
||||||
|
if (p1.z < clipPlaneDistance && p2.z < clipPlaneDistance)
|
||||||
|
{
|
||||||
|
return {};
|
||||||
|
}
|
||||||
|
// We don't need to compute an intersection if both points are
|
||||||
|
// in front of us
|
||||||
|
if (p1.z > clipPlaneDistance && p2.z > clipPlaneDistance)
|
||||||
|
{
|
||||||
|
return {p1, p2};
|
||||||
|
}
|
||||||
|
// We don't really want to compute an intersection if both Z coordinates
|
||||||
|
// are sufficiently close to each other
|
||||||
|
if (std::abs(p1.z - p2.z) < 0.0001) // The number here is chosen arbitrarily
|
||||||
|
{
|
||||||
|
return {p1, p2};
|
||||||
|
}
|
||||||
|
// We compute the intersection as such:
|
||||||
|
// zi = (1 - alpha) * p1.z + alpha * p2.z = clipPlaneDistance
|
||||||
|
// alpha = (p1.z - clipPlaneDistance) / (p1.z - p2.z)
|
||||||
|
double alpha = (p1.z - clipPlaneDistance) / (p1.z - p2.z);
|
||||||
|
Point3f clipPlanePoint{
|
||||||
|
static_cast<float>((1 - alpha) * p1.x + alpha * p2.x),
|
||||||
|
static_cast<float>((1 - alpha) * p1.y + alpha * p2.y),
|
||||||
|
clipPlaneDistance
|
||||||
|
};
|
||||||
|
if (p1.z < clipPlaneDistance)
|
||||||
|
{
|
||||||
|
return {clipPlanePoint, p2};
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
return {p1, clipPlanePoint};
|
||||||
|
}
|
||||||
|
// Unreachable?
|
||||||
}
|
}
|
||||||
|
|
||||||
void _drawAxis(InputOutputArray _image, InputArray _cameraMatrix, InputArray _distCoeffs,
|
void _drawAxis(InputOutputArray _image, InputArray _cameraMatrix, InputArray _distCoeffs,
|
||||||
@@ -186,647 +330,23 @@ void _drawAxis(InputOutputArray _image, InputArray _cameraMatrix, InputArray _di
|
|||||||
axisPoints.push_back(Point3f(length, 0, 0));
|
axisPoints.push_back(Point3f(length, 0, 0));
|
||||||
axisPoints.push_back(Point3f(0, length, 0));
|
axisPoints.push_back(Point3f(0, length, 0));
|
||||||
axisPoints.push_back(Point3f(0, 0, length));
|
axisPoints.push_back(Point3f(0, 0, length));
|
||||||
std::vector<Point3f> imagePointsZ;
|
auto camAxisPoints = worldToCamera(axisPoints, _rvec.getMat(), _tvec.getMat());
|
||||||
_projectPoints(axisPoints, _rvec, _tvec, _cameraMatrix, _distCoeffs, imagePointsZ);
|
auto axisX = cameraToScreen(lineClip(camAxisPoints[0], camAxisPoints[1]), _cameraMatrix.getMat(), _distCoeffs.getMat());
|
||||||
|
auto axisY = cameraToScreen(lineClip(camAxisPoints[0], camAxisPoints[2]), _cameraMatrix.getMat(), _distCoeffs.getMat());
|
||||||
// draw axis lines
|
auto axisZ = cameraToScreen(lineClip(camAxisPoints[0], camAxisPoints[3]), _cameraMatrix.getMat(), _distCoeffs.getMat());
|
||||||
linePartial(_image, imagePointsZ[0], imagePointsZ[1], Scalar(0, 0, 255), 3);
|
if (axisX.size() > 0)
|
||||||
linePartial(_image, imagePointsZ[0], imagePointsZ[2], Scalar(0, 255, 0), 3);
|
|
||||||
linePartial(_image, imagePointsZ[0], imagePointsZ[3], Scalar(255, 0, 0), 3);
|
|
||||||
}
|
|
||||||
|
|
||||||
static CvMat _cvMat(const cv::Mat& m)
|
|
||||||
{
|
|
||||||
CvMat self;
|
|
||||||
CV_DbgAssert(m.dims <= 2);
|
|
||||||
self = cvMat(m.rows, m.dims == 1 ? 1 : m.cols, m.type(), m.data);
|
|
||||||
self.step = (int)m.step[0];
|
|
||||||
self.type = (self.type & ~cv::Mat::CONTINUOUS_FLAG) | (m.flags & cv::Mat::CONTINUOUS_FLAG);
|
|
||||||
return self;
|
|
||||||
}
|
|
||||||
|
|
||||||
static void _projectPoints( InputArray _opoints,
|
|
||||||
InputArray _rvec,
|
|
||||||
InputArray _tvec,
|
|
||||||
InputArray _cameraMatrix,
|
|
||||||
InputArray _distCoeffs,
|
|
||||||
OutputArray _ipoints,
|
|
||||||
OutputArray _jacobian,
|
|
||||||
double aspectRatio )
|
|
||||||
{
|
|
||||||
Mat opoints = _opoints.getMat();
|
|
||||||
int npoints = opoints.checkVector(3), depth = opoints.depth();
|
|
||||||
CV_Assert(npoints >= 0 && (depth == CV_32F || depth == CV_64F));
|
|
||||||
|
|
||||||
CvMat dpdrot, dpdt, dpdf, dpdc, dpddist;
|
|
||||||
CvMat *pdpdrot = 0, *pdpdt = 0, *pdpdf = 0, *pdpdc = 0, *pdpddist = 0;
|
|
||||||
|
|
||||||
CV_Assert(_ipoints.needed());
|
|
||||||
|
|
||||||
_ipoints.create(npoints, 1, CV_MAKETYPE(depth, 3), -1, true);
|
|
||||||
Mat imagePoints = _ipoints.getMat();
|
|
||||||
CvMat c_imagePoints = _cvMat(imagePoints);
|
|
||||||
CvMat c_objectPoints = _cvMat(opoints);
|
|
||||||
Mat cameraMatrix = _cameraMatrix.getMat();
|
|
||||||
|
|
||||||
Mat rvec = _rvec.getMat(), tvec = _tvec.getMat();
|
|
||||||
CvMat c_cameraMatrix = _cvMat(cameraMatrix);
|
|
||||||
CvMat c_rvec = _cvMat(rvec), c_tvec = _cvMat(tvec);
|
|
||||||
|
|
||||||
double dc0buf[5] = {0};
|
|
||||||
Mat dc0(5, 1, CV_64F, dc0buf);
|
|
||||||
Mat distCoeffs = _distCoeffs.getMat();
|
|
||||||
if (distCoeffs.empty())
|
|
||||||
distCoeffs = dc0;
|
|
||||||
CvMat c_distCoeffs = _cvMat(distCoeffs);
|
|
||||||
int ndistCoeffs = distCoeffs.rows + distCoeffs.cols - 1;
|
|
||||||
|
|
||||||
Mat jacobian;
|
|
||||||
if (_jacobian.needed())
|
|
||||||
{
|
{
|
||||||
_jacobian.create(npoints * 2, 3 + 3 + 2 + 2 + ndistCoeffs, CV_64F);
|
line(_image, Point2f{axisX[0].x, axisX[0].y}, Point2f{axisX[1].x, axisX[1].y},
|
||||||
jacobian = _jacobian.getMat();
|
Scalar(0, 0, 255), 3);
|
||||||
pdpdrot = &(dpdrot = _cvMat(jacobian.colRange(0, 3)));
|
}
|
||||||
pdpdt = &(dpdt = _cvMat(jacobian.colRange(3, 6)));
|
if (axisY.size() > 0)
|
||||||
pdpdf = &(dpdf = _cvMat(jacobian.colRange(6, 8)));
|
{
|
||||||
pdpdc = &(dpdc = _cvMat(jacobian.colRange(8, 10)));
|
line(_image, Point2f{axisY[0].x, axisY[0].y}, Point2f{axisY[1].x, axisY[1].y},
|
||||||
pdpddist = &(dpddist = _cvMat(jacobian.colRange(10, 10 + ndistCoeffs)));
|
Scalar(0, 255, 0), 3);
|
||||||
|
}
|
||||||
|
if (axisZ.size() > 0)
|
||||||
|
{
|
||||||
|
line(_image, Point2f{axisZ[0].x, axisZ[0].y}, Point2f{axisZ[1].x, axisZ[1].y},
|
||||||
|
Scalar(255, 0, 0), 3);
|
||||||
}
|
}
|
||||||
|
|
||||||
_cvProjectPoints2(&c_objectPoints, &c_rvec, &c_tvec, &c_cameraMatrix, &c_distCoeffs,
|
|
||||||
&c_imagePoints, pdpdrot, pdpdt, pdpdf, pdpdc, pdpddist, aspectRatio);
|
|
||||||
}
|
|
||||||
|
|
||||||
namespace _detail
|
|
||||||
{
|
|
||||||
template <typename FLOAT>
|
|
||||||
void computeTiltProjectionMatrix(FLOAT tauX,
|
|
||||||
FLOAT tauY,
|
|
||||||
Matx<FLOAT, 3, 3>* matTilt = 0,
|
|
||||||
Matx<FLOAT, 3, 3>* dMatTiltdTauX = 0,
|
|
||||||
Matx<FLOAT, 3, 3>* dMatTiltdTauY = 0,
|
|
||||||
Matx<FLOAT, 3, 3>* invMatTilt = 0)
|
|
||||||
{
|
|
||||||
FLOAT cTauX = cos(tauX);
|
|
||||||
FLOAT sTauX = sin(tauX);
|
|
||||||
FLOAT cTauY = cos(tauY);
|
|
||||||
FLOAT sTauY = sin(tauY);
|
|
||||||
Matx<FLOAT, 3, 3> matRotX = Matx<FLOAT, 3, 3>(1,0,0,0,cTauX,sTauX,0,-sTauX,cTauX);
|
|
||||||
Matx<FLOAT, 3, 3> matRotY = Matx<FLOAT, 3, 3>(cTauY,0,-sTauY,0,1,0,sTauY,0,cTauY);
|
|
||||||
Matx<FLOAT, 3, 3> matRotXY = matRotY * matRotX;
|
|
||||||
Matx<FLOAT, 3, 3> matProjZ = Matx<FLOAT, 3, 3>(matRotXY(2,2),0,-matRotXY(0,2),0,matRotXY(2,2),-matRotXY(1,2),0,0,1);
|
|
||||||
if (matTilt)
|
|
||||||
{
|
|
||||||
// Matrix for trapezoidal distortion of tilted image sensor
|
|
||||||
*matTilt = matProjZ * matRotXY;
|
|
||||||
}
|
|
||||||
if (dMatTiltdTauX)
|
|
||||||
{
|
|
||||||
// Derivative with respect to tauX
|
|
||||||
Matx<FLOAT, 3, 3> dMatRotXYdTauX = matRotY * Matx<FLOAT, 3, 3>(0,0,0,0,-sTauX,cTauX,0,-cTauX,-sTauX);
|
|
||||||
Matx<FLOAT, 3, 3> dMatProjZdTauX = Matx<FLOAT, 3, 3>(dMatRotXYdTauX(2,2),0,-dMatRotXYdTauX(0,2),
|
|
||||||
0,dMatRotXYdTauX(2,2),-dMatRotXYdTauX(1,2),0,0,0);
|
|
||||||
*dMatTiltdTauX = (matProjZ * dMatRotXYdTauX) + (dMatProjZdTauX * matRotXY);
|
|
||||||
}
|
|
||||||
if (dMatTiltdTauY)
|
|
||||||
{
|
|
||||||
// Derivative with respect to tauY
|
|
||||||
Matx<FLOAT, 3, 3> dMatRotXYdTauY = Matx<FLOAT, 3, 3>(-sTauY,0,-cTauY,0,0,0,cTauY,0,-sTauY) * matRotX;
|
|
||||||
Matx<FLOAT, 3, 3> dMatProjZdTauY = Matx<FLOAT, 3, 3>(dMatRotXYdTauY(2,2),0,-dMatRotXYdTauY(0,2),
|
|
||||||
0,dMatRotXYdTauY(2,2),-dMatRotXYdTauY(1,2),0,0,0);
|
|
||||||
*dMatTiltdTauY = (matProjZ * dMatRotXYdTauY) + (dMatProjZdTauY * matRotXY);
|
|
||||||
}
|
|
||||||
if (invMatTilt)
|
|
||||||
{
|
|
||||||
FLOAT inv = 1./matRotXY(2,2);
|
|
||||||
Matx<FLOAT, 3, 3> invMatProjZ = Matx<FLOAT, 3, 3>(inv,0,inv*matRotXY(0,2),0,inv,inv*matRotXY(1,2),0,0,1);
|
|
||||||
*invMatTilt = matRotXY.t()*invMatProjZ;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
static const char* cvDistCoeffErr = "Distortion coefficients must be 1x4, 4x1, 1x5, 5x1, 1x8, 8x1, 1x12, 12x1, 1x14 or 14x1 floating-point vector";
|
|
||||||
|
|
||||||
static void _cvProjectPoints2Internal( const CvMat* objectPoints,
|
|
||||||
const CvMat* r_vec,
|
|
||||||
const CvMat* t_vec,
|
|
||||||
const CvMat* A,
|
|
||||||
const CvMat* distCoeffs,
|
|
||||||
CvMat* imagePoints, CvMat* dpdr CV_DEFAULT(NULL),
|
|
||||||
CvMat* dpdt CV_DEFAULT(NULL), CvMat* dpdf CV_DEFAULT(NULL),
|
|
||||||
CvMat* dpdc CV_DEFAULT(NULL), CvMat* dpdk CV_DEFAULT(NULL),
|
|
||||||
CvMat* dpdo CV_DEFAULT(NULL),
|
|
||||||
double aspectRatio CV_DEFAULT(0) )
|
|
||||||
{
|
|
||||||
Ptr<CvMat> matM, _m;
|
|
||||||
Ptr<CvMat> _dpdr, _dpdt, _dpdc, _dpdf, _dpdk;
|
|
||||||
Ptr<CvMat> _dpdo;
|
|
||||||
|
|
||||||
int i, j, count;
|
|
||||||
int calc_derivatives;
|
|
||||||
const CvPoint3D64f* M;
|
|
||||||
CvPoint3D64f* m;
|
|
||||||
double r[3], R[9], dRdr[27], t[3], a[9], k[14] = {0,0,0,0,0,0,0,0,0,0,0,0,0,0}, fx, fy, cx, cy;
|
|
||||||
Matx33d matTilt = Matx33d::eye();
|
|
||||||
Matx33d dMatTiltdTauX(0,0,0,0,0,0,0,-1,0);
|
|
||||||
Matx33d dMatTiltdTauY(0,0,0,0,0,0,1,0,0);
|
|
||||||
CvMat _r, _t, _a = cvMat( 3, 3, CV_64F, a ), _k;
|
|
||||||
CvMat matR = cvMat( 3, 3, CV_64F, R ), _dRdr = cvMat( 3, 9, CV_64F, dRdr );
|
|
||||||
double *dpdr_p = 0, *dpdt_p = 0, *dpdk_p = 0, *dpdf_p = 0, *dpdc_p = 0;
|
|
||||||
double* dpdo_p = 0;
|
|
||||||
int dpdr_step = 0, dpdt_step = 0, dpdk_step = 0, dpdf_step = 0, dpdc_step = 0;
|
|
||||||
int dpdo_step = 0;
|
|
||||||
bool fixedAspectRatio = aspectRatio > FLT_EPSILON;
|
|
||||||
|
|
||||||
if( !CV_IS_MAT(objectPoints) || !CV_IS_MAT(r_vec) ||
|
|
||||||
!CV_IS_MAT(t_vec) || !CV_IS_MAT(A) ||
|
|
||||||
/*!CV_IS_MAT(distCoeffs) ||*/ !CV_IS_MAT(imagePoints) )
|
|
||||||
CV_Error( CV_StsBadArg, "One of required arguments is not a valid matrix" );
|
|
||||||
|
|
||||||
int total = objectPoints->rows * objectPoints->cols * CV_MAT_CN(objectPoints->type);
|
|
||||||
if(total % 3 != 0)
|
|
||||||
{
|
|
||||||
//we have stopped support of homogeneous coordinates because it cause ambiguity in interpretation of the input data
|
|
||||||
CV_Error( CV_StsBadArg, "Homogeneous coordinates are not supported" );
|
|
||||||
}
|
|
||||||
count = total / 3;
|
|
||||||
|
|
||||||
if( CV_IS_CONT_MAT(objectPoints->type) &&
|
|
||||||
(CV_MAT_DEPTH(objectPoints->type) == CV_32F || CV_MAT_DEPTH(objectPoints->type) == CV_64F)&&
|
|
||||||
((objectPoints->rows == 1 && CV_MAT_CN(objectPoints->type) == 3) ||
|
|
||||||
(objectPoints->rows == count && CV_MAT_CN(objectPoints->type)*objectPoints->cols == 3) ||
|
|
||||||
(objectPoints->rows == 3 && CV_MAT_CN(objectPoints->type) == 1 && objectPoints->cols == count)))
|
|
||||||
{
|
|
||||||
matM.reset(cvCreateMat( objectPoints->rows, objectPoints->cols, CV_MAKETYPE(CV_64F,CV_MAT_CN(objectPoints->type)) ));
|
|
||||||
cvConvert(objectPoints, matM);
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
// matM = cvCreateMat( 1, count, CV_64FC3 );
|
|
||||||
// cvConvertPointsHomogeneous( objectPoints, matM );
|
|
||||||
CV_Error( CV_StsBadArg, "Homogeneous coordinates are not supported" );
|
|
||||||
}
|
|
||||||
|
|
||||||
if( CV_IS_CONT_MAT(imagePoints->type) &&
|
|
||||||
(CV_MAT_DEPTH(imagePoints->type) == CV_32F || CV_MAT_DEPTH(imagePoints->type) == CV_64F) &&
|
|
||||||
((imagePoints->rows == 1 && CV_MAT_CN(imagePoints->type) == 3) ||
|
|
||||||
(imagePoints->rows == count && CV_MAT_CN(imagePoints->type)*imagePoints->cols == 3) ||
|
|
||||||
(imagePoints->rows == 3 && CV_MAT_CN(imagePoints->type) == 1 && imagePoints->cols == count)))
|
|
||||||
{
|
|
||||||
_m.reset(cvCreateMat( imagePoints->rows, imagePoints->cols, CV_MAKETYPE(CV_64F,CV_MAT_CN(imagePoints->type)) ));
|
|
||||||
cvConvert(imagePoints, _m);
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
// _m = cvCreateMat( 1, count, CV_64FC2 );
|
|
||||||
CV_Error( CV_StsBadArg, "Homogeneous coordinates are not supported" );
|
|
||||||
}
|
|
||||||
|
|
||||||
M = (CvPoint3D64f*)matM->data.db;
|
|
||||||
m = (CvPoint3D64f*)_m->data.db;
|
|
||||||
|
|
||||||
if( (CV_MAT_DEPTH(r_vec->type) != CV_64F && CV_MAT_DEPTH(r_vec->type) != CV_32F) ||
|
|
||||||
(((r_vec->rows != 1 && r_vec->cols != 1) ||
|
|
||||||
r_vec->rows*r_vec->cols*CV_MAT_CN(r_vec->type) != 3) &&
|
|
||||||
((r_vec->rows != 3 && r_vec->cols != 3) || CV_MAT_CN(r_vec->type) != 1)))
|
|
||||||
CV_Error( CV_StsBadArg, "Rotation must be represented by 1x3 or 3x1 "
|
|
||||||
"floating-point rotation vector, or 3x3 rotation matrix" );
|
|
||||||
|
|
||||||
if( r_vec->rows == 3 && r_vec->cols == 3 )
|
|
||||||
{
|
|
||||||
_r = cvMat( 3, 1, CV_64FC1, r );
|
|
||||||
cvRodrigues2( r_vec, &_r );
|
|
||||||
cvRodrigues2( &_r, &matR, &_dRdr );
|
|
||||||
cvCopy( r_vec, &matR );
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
_r = cvMat( r_vec->rows, r_vec->cols, CV_MAKETYPE(CV_64F,CV_MAT_CN(r_vec->type)), r );
|
|
||||||
cvConvert( r_vec, &_r );
|
|
||||||
cvRodrigues2( &_r, &matR, &_dRdr );
|
|
||||||
}
|
|
||||||
|
|
||||||
if( (CV_MAT_DEPTH(t_vec->type) != CV_64F && CV_MAT_DEPTH(t_vec->type) != CV_32F) ||
|
|
||||||
(t_vec->rows != 1 && t_vec->cols != 1) ||
|
|
||||||
t_vec->rows*t_vec->cols*CV_MAT_CN(t_vec->type) != 3 )
|
|
||||||
CV_Error( CV_StsBadArg,
|
|
||||||
"Translation vector must be 1x3 or 3x1 floating-point vector" );
|
|
||||||
|
|
||||||
_t = cvMat( t_vec->rows, t_vec->cols, CV_MAKETYPE(CV_64F,CV_MAT_CN(t_vec->type)), t );
|
|
||||||
cvConvert( t_vec, &_t );
|
|
||||||
|
|
||||||
if( (CV_MAT_TYPE(A->type) != CV_64FC1 && CV_MAT_TYPE(A->type) != CV_32FC1) ||
|
|
||||||
A->rows != 3 || A->cols != 3 )
|
|
||||||
CV_Error( CV_StsBadArg, "Instrinsic parameters must be 3x3 floating-point matrix" );
|
|
||||||
|
|
||||||
cvConvert( A, &_a );
|
|
||||||
fx = a[0]; fy = a[4];
|
|
||||||
cx = a[2]; cy = a[5];
|
|
||||||
|
|
||||||
if( fixedAspectRatio )
|
|
||||||
fx = fy*aspectRatio;
|
|
||||||
|
|
||||||
if( distCoeffs )
|
|
||||||
{
|
|
||||||
if( !CV_IS_MAT(distCoeffs) ||
|
|
||||||
(CV_MAT_DEPTH(distCoeffs->type) != CV_64F &&
|
|
||||||
CV_MAT_DEPTH(distCoeffs->type) != CV_32F) ||
|
|
||||||
(distCoeffs->rows != 1 && distCoeffs->cols != 1) ||
|
|
||||||
(distCoeffs->rows*distCoeffs->cols*CV_MAT_CN(distCoeffs->type) != 4 &&
|
|
||||||
distCoeffs->rows*distCoeffs->cols*CV_MAT_CN(distCoeffs->type) != 5 &&
|
|
||||||
distCoeffs->rows*distCoeffs->cols*CV_MAT_CN(distCoeffs->type) != 8 &&
|
|
||||||
distCoeffs->rows*distCoeffs->cols*CV_MAT_CN(distCoeffs->type) != 12 &&
|
|
||||||
distCoeffs->rows*distCoeffs->cols*CV_MAT_CN(distCoeffs->type) != 14) )
|
|
||||||
CV_Error( CV_StsBadArg, cvDistCoeffErr );
|
|
||||||
|
|
||||||
_k = cvMat( distCoeffs->rows, distCoeffs->cols,
|
|
||||||
CV_MAKETYPE(CV_64F,CV_MAT_CN(distCoeffs->type)), k );
|
|
||||||
cvConvert( distCoeffs, &_k );
|
|
||||||
if(k[12] != 0 || k[13] != 0)
|
|
||||||
{
|
|
||||||
_detail::computeTiltProjectionMatrix(k[12], k[13],
|
|
||||||
&matTilt, &dMatTiltdTauX, &dMatTiltdTauY);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if( dpdr )
|
|
||||||
{
|
|
||||||
if( !CV_IS_MAT(dpdr) ||
|
|
||||||
(CV_MAT_TYPE(dpdr->type) != CV_32FC1 &&
|
|
||||||
CV_MAT_TYPE(dpdr->type) != CV_64FC1) ||
|
|
||||||
dpdr->rows != count*2 || dpdr->cols != 3 )
|
|
||||||
CV_Error( CV_StsBadArg, "dp/drot must be 2Nx3 floating-point matrix" );
|
|
||||||
|
|
||||||
if( CV_MAT_TYPE(dpdr->type) == CV_64FC1 )
|
|
||||||
{
|
|
||||||
_dpdr.reset(cvCloneMat(dpdr));
|
|
||||||
}
|
|
||||||
else
|
|
||||||
_dpdr.reset(cvCreateMat( 2*count, 3, CV_64FC1 ));
|
|
||||||
dpdr_p = _dpdr->data.db;
|
|
||||||
dpdr_step = _dpdr->step/sizeof(dpdr_p[0]);
|
|
||||||
}
|
|
||||||
|
|
||||||
if( dpdt )
|
|
||||||
{
|
|
||||||
if( !CV_IS_MAT(dpdt) ||
|
|
||||||
(CV_MAT_TYPE(dpdt->type) != CV_32FC1 &&
|
|
||||||
CV_MAT_TYPE(dpdt->type) != CV_64FC1) ||
|
|
||||||
dpdt->rows != count*2 || dpdt->cols != 3 )
|
|
||||||
CV_Error( CV_StsBadArg, "dp/dT must be 2Nx3 floating-point matrix" );
|
|
||||||
|
|
||||||
if( CV_MAT_TYPE(dpdt->type) == CV_64FC1 )
|
|
||||||
{
|
|
||||||
_dpdt.reset(cvCloneMat(dpdt));
|
|
||||||
}
|
|
||||||
else
|
|
||||||
_dpdt.reset(cvCreateMat( 2*count, 3, CV_64FC1 ));
|
|
||||||
dpdt_p = _dpdt->data.db;
|
|
||||||
dpdt_step = _dpdt->step/sizeof(dpdt_p[0]);
|
|
||||||
}
|
|
||||||
|
|
||||||
if( dpdf )
|
|
||||||
{
|
|
||||||
if( !CV_IS_MAT(dpdf) ||
|
|
||||||
(CV_MAT_TYPE(dpdf->type) != CV_32FC1 && CV_MAT_TYPE(dpdf->type) != CV_64FC1) ||
|
|
||||||
dpdf->rows != count*2 || dpdf->cols != 2 )
|
|
||||||
CV_Error( CV_StsBadArg, "dp/df must be 2Nx2 floating-point matrix" );
|
|
||||||
|
|
||||||
if( CV_MAT_TYPE(dpdf->type) == CV_64FC1 )
|
|
||||||
{
|
|
||||||
_dpdf.reset(cvCloneMat(dpdf));
|
|
||||||
}
|
|
||||||
else
|
|
||||||
_dpdf.reset(cvCreateMat( 2*count, 2, CV_64FC1 ));
|
|
||||||
dpdf_p = _dpdf->data.db;
|
|
||||||
dpdf_step = _dpdf->step/sizeof(dpdf_p[0]);
|
|
||||||
}
|
|
||||||
|
|
||||||
if( dpdc )
|
|
||||||
{
|
|
||||||
if( !CV_IS_MAT(dpdc) ||
|
|
||||||
(CV_MAT_TYPE(dpdc->type) != CV_32FC1 && CV_MAT_TYPE(dpdc->type) != CV_64FC1) ||
|
|
||||||
dpdc->rows != count*2 || dpdc->cols != 2 )
|
|
||||||
CV_Error( CV_StsBadArg, "dp/dc must be 2Nx2 floating-point matrix" );
|
|
||||||
|
|
||||||
if( CV_MAT_TYPE(dpdc->type) == CV_64FC1 )
|
|
||||||
{
|
|
||||||
_dpdc.reset(cvCloneMat(dpdc));
|
|
||||||
}
|
|
||||||
else
|
|
||||||
_dpdc.reset(cvCreateMat( 2*count, 2, CV_64FC1 ));
|
|
||||||
dpdc_p = _dpdc->data.db;
|
|
||||||
dpdc_step = _dpdc->step/sizeof(dpdc_p[0]);
|
|
||||||
}
|
|
||||||
|
|
||||||
if( dpdk )
|
|
||||||
{
|
|
||||||
if( !CV_IS_MAT(dpdk) ||
|
|
||||||
(CV_MAT_TYPE(dpdk->type) != CV_32FC1 && CV_MAT_TYPE(dpdk->type) != CV_64FC1) ||
|
|
||||||
dpdk->rows != count*2 || (dpdk->cols != 14 && dpdk->cols != 12 && dpdk->cols != 8 && dpdk->cols != 5 && dpdk->cols != 4 && dpdk->cols != 2) )
|
|
||||||
CV_Error( CV_StsBadArg, "dp/df must be 2Nx14, 2Nx12, 2Nx8, 2Nx5, 2Nx4 or 2Nx2 floating-point matrix" );
|
|
||||||
|
|
||||||
if( !distCoeffs )
|
|
||||||
CV_Error( CV_StsNullPtr, "distCoeffs is NULL while dpdk is not" );
|
|
||||||
|
|
||||||
if( CV_MAT_TYPE(dpdk->type) == CV_64FC1 )
|
|
||||||
{
|
|
||||||
_dpdk.reset(cvCloneMat(dpdk));
|
|
||||||
}
|
|
||||||
else
|
|
||||||
_dpdk.reset(cvCreateMat( dpdk->rows, dpdk->cols, CV_64FC1 ));
|
|
||||||
dpdk_p = _dpdk->data.db;
|
|
||||||
dpdk_step = _dpdk->step/sizeof(dpdk_p[0]);
|
|
||||||
}
|
|
||||||
|
|
||||||
if( dpdo )
|
|
||||||
{
|
|
||||||
if( !CV_IS_MAT( dpdo ) || ( CV_MAT_TYPE( dpdo->type ) != CV_32FC1
|
|
||||||
&& CV_MAT_TYPE( dpdo->type ) != CV_64FC1 )
|
|
||||||
|| dpdo->rows != count * 2 || dpdo->cols != count * 3 )
|
|
||||||
CV_Error( CV_StsBadArg, "dp/do must be 2Nx3N floating-point matrix" );
|
|
||||||
|
|
||||||
if( CV_MAT_TYPE( dpdo->type ) == CV_64FC1 )
|
|
||||||
{
|
|
||||||
_dpdo.reset( cvCloneMat( dpdo ) );
|
|
||||||
}
|
|
||||||
else
|
|
||||||
_dpdo.reset( cvCreateMat( 2 * count, 3 * count, CV_64FC1 ) );
|
|
||||||
cvZero(_dpdo);
|
|
||||||
dpdo_p = _dpdo->data.db;
|
|
||||||
dpdo_step = _dpdo->step / sizeof( dpdo_p[0] );
|
|
||||||
}
|
|
||||||
|
|
||||||
calc_derivatives = dpdr || dpdt || dpdf || dpdc || dpdk || dpdo;
|
|
||||||
|
|
||||||
for( i = 0; i < count; i++ )
|
|
||||||
{
|
|
||||||
double X = M[i].x, Y = M[i].y, Z = M[i].z;
|
|
||||||
double x = R[0]*X + R[1]*Y + R[2]*Z + t[0];
|
|
||||||
double y = R[3]*X + R[4]*Y + R[5]*Z + t[1];
|
|
||||||
double z = R[6]*X + R[7]*Y + R[8]*Z + t[2];
|
|
||||||
double r2, r4, r6, a1, a2, a3, cdist, icdist2;
|
|
||||||
double xd, yd, xd0, yd0, invProj;
|
|
||||||
Vec3d vecTilt;
|
|
||||||
Vec3d dVecTilt;
|
|
||||||
Matx22d dMatTilt;
|
|
||||||
Vec2d dXdYd;
|
|
||||||
|
|
||||||
double z0 = z;
|
|
||||||
z = z ? 1./z : 1;
|
|
||||||
x *= z; y *= z;
|
|
||||||
|
|
||||||
r2 = x*x + y*y;
|
|
||||||
r4 = r2*r2;
|
|
||||||
r6 = r4*r2;
|
|
||||||
a1 = 2*x*y;
|
|
||||||
a2 = r2 + 2*x*x;
|
|
||||||
a3 = r2 + 2*y*y;
|
|
||||||
cdist = 1 + k[0]*r2 + k[1]*r4 + k[4]*r6;
|
|
||||||
icdist2 = 1./(1 + k[5]*r2 + k[6]*r4 + k[7]*r6);
|
|
||||||
xd0 = x*cdist*icdist2 + k[2]*a1 + k[3]*a2 + k[8]*r2+k[9]*r4;
|
|
||||||
yd0 = y*cdist*icdist2 + k[2]*a3 + k[3]*a1 + k[10]*r2+k[11]*r4;
|
|
||||||
|
|
||||||
// additional distortion by projecting onto a tilt plane
|
|
||||||
vecTilt = matTilt*Vec3d(xd0, yd0, 1);
|
|
||||||
invProj = vecTilt(2) ? 1./vecTilt(2) : 1;
|
|
||||||
xd = invProj * vecTilt(0);
|
|
||||||
yd = invProj * vecTilt(1);
|
|
||||||
|
|
||||||
m[i].x = xd*fx + cx;
|
|
||||||
m[i].y = yd*fy + cy;
|
|
||||||
m[i].z = z; // Just put the projected Z coordinate here, we mainly care about the sign
|
|
||||||
|
|
||||||
if( calc_derivatives )
|
|
||||||
{
|
|
||||||
if( dpdc_p )
|
|
||||||
{
|
|
||||||
dpdc_p[0] = 1; dpdc_p[1] = 0; // dp_xdc_x; dp_xdc_y
|
|
||||||
dpdc_p[dpdc_step] = 0;
|
|
||||||
dpdc_p[dpdc_step+1] = 1;
|
|
||||||
dpdc_p += dpdc_step*2;
|
|
||||||
}
|
|
||||||
|
|
||||||
if( dpdf_p )
|
|
||||||
{
|
|
||||||
if( fixedAspectRatio )
|
|
||||||
{
|
|
||||||
dpdf_p[0] = 0; dpdf_p[1] = xd*aspectRatio; // dp_xdf_x; dp_xdf_y
|
|
||||||
dpdf_p[dpdf_step] = 0;
|
|
||||||
dpdf_p[dpdf_step+1] = yd;
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
dpdf_p[0] = xd; dpdf_p[1] = 0;
|
|
||||||
dpdf_p[dpdf_step] = 0;
|
|
||||||
dpdf_p[dpdf_step+1] = yd;
|
|
||||||
}
|
|
||||||
dpdf_p += dpdf_step*2;
|
|
||||||
}
|
|
||||||
for (int row = 0; row < 2; ++row)
|
|
||||||
for (int col = 0; col < 2; ++col)
|
|
||||||
dMatTilt(row,col) = matTilt(row,col)*vecTilt(2)
|
|
||||||
- matTilt(2,col)*vecTilt(row);
|
|
||||||
double invProjSquare = (invProj*invProj);
|
|
||||||
dMatTilt *= invProjSquare;
|
|
||||||
if( dpdk_p )
|
|
||||||
{
|
|
||||||
dXdYd = dMatTilt*Vec2d(x*icdist2*r2, y*icdist2*r2);
|
|
||||||
dpdk_p[0] = fx*dXdYd(0);
|
|
||||||
dpdk_p[dpdk_step] = fy*dXdYd(1);
|
|
||||||
dXdYd = dMatTilt*Vec2d(x*icdist2*r4, y*icdist2*r4);
|
|
||||||
dpdk_p[1] = fx*dXdYd(0);
|
|
||||||
dpdk_p[dpdk_step+1] = fy*dXdYd(1);
|
|
||||||
if( _dpdk->cols > 2 )
|
|
||||||
{
|
|
||||||
dXdYd = dMatTilt*Vec2d(a1, a3);
|
|
||||||
dpdk_p[2] = fx*dXdYd(0);
|
|
||||||
dpdk_p[dpdk_step+2] = fy*dXdYd(1);
|
|
||||||
dXdYd = dMatTilt*Vec2d(a2, a1);
|
|
||||||
dpdk_p[3] = fx*dXdYd(0);
|
|
||||||
dpdk_p[dpdk_step+3] = fy*dXdYd(1);
|
|
||||||
if( _dpdk->cols > 4 )
|
|
||||||
{
|
|
||||||
dXdYd = dMatTilt*Vec2d(x*icdist2*r6, y*icdist2*r6);
|
|
||||||
dpdk_p[4] = fx*dXdYd(0);
|
|
||||||
dpdk_p[dpdk_step+4] = fy*dXdYd(1);
|
|
||||||
|
|
||||||
if( _dpdk->cols > 5 )
|
|
||||||
{
|
|
||||||
dXdYd = dMatTilt*Vec2d(
|
|
||||||
x*cdist*(-icdist2)*icdist2*r2, y*cdist*(-icdist2)*icdist2*r2);
|
|
||||||
dpdk_p[5] = fx*dXdYd(0);
|
|
||||||
dpdk_p[dpdk_step+5] = fy*dXdYd(1);
|
|
||||||
dXdYd = dMatTilt*Vec2d(
|
|
||||||
x*cdist*(-icdist2)*icdist2*r4, y*cdist*(-icdist2)*icdist2*r4);
|
|
||||||
dpdk_p[6] = fx*dXdYd(0);
|
|
||||||
dpdk_p[dpdk_step+6] = fy*dXdYd(1);
|
|
||||||
dXdYd = dMatTilt*Vec2d(
|
|
||||||
x*cdist*(-icdist2)*icdist2*r6, y*cdist*(-icdist2)*icdist2*r6);
|
|
||||||
dpdk_p[7] = fx*dXdYd(0);
|
|
||||||
dpdk_p[dpdk_step+7] = fy*dXdYd(1);
|
|
||||||
if( _dpdk->cols > 8 )
|
|
||||||
{
|
|
||||||
dXdYd = dMatTilt*Vec2d(r2, 0);
|
|
||||||
dpdk_p[8] = fx*dXdYd(0); //s1
|
|
||||||
dpdk_p[dpdk_step+8] = fy*dXdYd(1); //s1
|
|
||||||
dXdYd = dMatTilt*Vec2d(r4, 0);
|
|
||||||
dpdk_p[9] = fx*dXdYd(0); //s2
|
|
||||||
dpdk_p[dpdk_step+9] = fy*dXdYd(1); //s2
|
|
||||||
dXdYd = dMatTilt*Vec2d(0, r2);
|
|
||||||
dpdk_p[10] = fx*dXdYd(0);//s3
|
|
||||||
dpdk_p[dpdk_step+10] = fy*dXdYd(1); //s3
|
|
||||||
dXdYd = dMatTilt*Vec2d(0, r4);
|
|
||||||
dpdk_p[11] = fx*dXdYd(0);//s4
|
|
||||||
dpdk_p[dpdk_step+11] = fy*dXdYd(1); //s4
|
|
||||||
if( _dpdk->cols > 12 )
|
|
||||||
{
|
|
||||||
dVecTilt = dMatTiltdTauX * Vec3d(xd0, yd0, 1);
|
|
||||||
dpdk_p[12] = fx * invProjSquare * (
|
|
||||||
dVecTilt(0) * vecTilt(2) - dVecTilt(2) * vecTilt(0));
|
|
||||||
dpdk_p[dpdk_step+12] = fy*invProjSquare * (
|
|
||||||
dVecTilt(1) * vecTilt(2) - dVecTilt(2) * vecTilt(1));
|
|
||||||
dVecTilt = dMatTiltdTauY * Vec3d(xd0, yd0, 1);
|
|
||||||
dpdk_p[13] = fx * invProjSquare * (
|
|
||||||
dVecTilt(0) * vecTilt(2) - dVecTilt(2) * vecTilt(0));
|
|
||||||
dpdk_p[dpdk_step+13] = fy * invProjSquare * (
|
|
||||||
dVecTilt(1) * vecTilt(2) - dVecTilt(2) * vecTilt(1));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
dpdk_p += dpdk_step*2;
|
|
||||||
}
|
|
||||||
|
|
||||||
if( dpdt_p )
|
|
||||||
{
|
|
||||||
double dxdt[] = { z, 0, -x*z }, dydt[] = { 0, z, -y*z };
|
|
||||||
for( j = 0; j < 3; j++ )
|
|
||||||
{
|
|
||||||
double dr2dt = 2*x*dxdt[j] + 2*y*dydt[j];
|
|
||||||
double dcdist_dt = k[0]*dr2dt + 2*k[1]*r2*dr2dt + 3*k[4]*r4*dr2dt;
|
|
||||||
double dicdist2_dt = -icdist2*icdist2*(k[5]*dr2dt + 2*k[6]*r2*dr2dt + 3*k[7]*r4*dr2dt);
|
|
||||||
double da1dt = 2*(x*dydt[j] + y*dxdt[j]);
|
|
||||||
double dmxdt = (dxdt[j]*cdist*icdist2 + x*dcdist_dt*icdist2 + x*cdist*dicdist2_dt +
|
|
||||||
k[2]*da1dt + k[3]*(dr2dt + 4*x*dxdt[j]) + k[8]*dr2dt + 2*r2*k[9]*dr2dt);
|
|
||||||
double dmydt = (dydt[j]*cdist*icdist2 + y*dcdist_dt*icdist2 + y*cdist*dicdist2_dt +
|
|
||||||
k[2]*(dr2dt + 4*y*dydt[j]) + k[3]*da1dt + k[10]*dr2dt + 2*r2*k[11]*dr2dt);
|
|
||||||
dXdYd = dMatTilt*Vec2d(dmxdt, dmydt);
|
|
||||||
dpdt_p[j] = fx*dXdYd(0);
|
|
||||||
dpdt_p[dpdt_step+j] = fy*dXdYd(1);
|
|
||||||
}
|
|
||||||
dpdt_p += dpdt_step*2;
|
|
||||||
}
|
|
||||||
|
|
||||||
if( dpdr_p )
|
|
||||||
{
|
|
||||||
double dx0dr[] =
|
|
||||||
{
|
|
||||||
X*dRdr[0] + Y*dRdr[1] + Z*dRdr[2],
|
|
||||||
X*dRdr[9] + Y*dRdr[10] + Z*dRdr[11],
|
|
||||||
X*dRdr[18] + Y*dRdr[19] + Z*dRdr[20]
|
|
||||||
};
|
|
||||||
double dy0dr[] =
|
|
||||||
{
|
|
||||||
X*dRdr[3] + Y*dRdr[4] + Z*dRdr[5],
|
|
||||||
X*dRdr[12] + Y*dRdr[13] + Z*dRdr[14],
|
|
||||||
X*dRdr[21] + Y*dRdr[22] + Z*dRdr[23]
|
|
||||||
};
|
|
||||||
double dz0dr[] =
|
|
||||||
{
|
|
||||||
X*dRdr[6] + Y*dRdr[7] + Z*dRdr[8],
|
|
||||||
X*dRdr[15] + Y*dRdr[16] + Z*dRdr[17],
|
|
||||||
X*dRdr[24] + Y*dRdr[25] + Z*dRdr[26]
|
|
||||||
};
|
|
||||||
for( j = 0; j < 3; j++ )
|
|
||||||
{
|
|
||||||
double dxdr = z*(dx0dr[j] - x*dz0dr[j]);
|
|
||||||
double dydr = z*(dy0dr[j] - y*dz0dr[j]);
|
|
||||||
double dr2dr = 2*x*dxdr + 2*y*dydr;
|
|
||||||
double dcdist_dr = (k[0] + 2*k[1]*r2 + 3*k[4]*r4)*dr2dr;
|
|
||||||
double dicdist2_dr = -icdist2*icdist2*(k[5] + 2*k[6]*r2 + 3*k[7]*r4)*dr2dr;
|
|
||||||
double da1dr = 2*(x*dydr + y*dxdr);
|
|
||||||
double dmxdr = (dxdr*cdist*icdist2 + x*dcdist_dr*icdist2 + x*cdist*dicdist2_dr +
|
|
||||||
k[2]*da1dr + k[3]*(dr2dr + 4*x*dxdr) + (k[8] + 2*r2*k[9])*dr2dr);
|
|
||||||
double dmydr = (dydr*cdist*icdist2 + y*dcdist_dr*icdist2 + y*cdist*dicdist2_dr +
|
|
||||||
k[2]*(dr2dr + 4*y*dydr) + k[3]*da1dr + (k[10] + 2*r2*k[11])*dr2dr);
|
|
||||||
dXdYd = dMatTilt*Vec2d(dmxdr, dmydr);
|
|
||||||
dpdr_p[j] = fx*dXdYd(0);
|
|
||||||
dpdr_p[dpdr_step+j] = fy*dXdYd(1);
|
|
||||||
}
|
|
||||||
dpdr_p += dpdr_step*2;
|
|
||||||
}
|
|
||||||
|
|
||||||
if( dpdo_p )
|
|
||||||
{
|
|
||||||
double dxdo[] = { z * ( R[0] - x * z * z0 * R[6] ),
|
|
||||||
z * ( R[1] - x * z * z0 * R[7] ),
|
|
||||||
z * ( R[2] - x * z * z0 * R[8] ) };
|
|
||||||
double dydo[] = { z * ( R[3] - y * z * z0 * R[6] ),
|
|
||||||
z * ( R[4] - y * z * z0 * R[7] ),
|
|
||||||
z * ( R[5] - y * z * z0 * R[8] ) };
|
|
||||||
for( j = 0; j < 3; j++ )
|
|
||||||
{
|
|
||||||
double dr2do = 2 * x * dxdo[j] + 2 * y * dydo[j];
|
|
||||||
double dr4do = 2 * r2 * dr2do;
|
|
||||||
double dr6do = 3 * r4 * dr2do;
|
|
||||||
double da1do = 2 * y * dxdo[j] + 2 * x * dydo[j];
|
|
||||||
double da2do = dr2do + 4 * x * dxdo[j];
|
|
||||||
double da3do = dr2do + 4 * y * dydo[j];
|
|
||||||
double dcdist_do
|
|
||||||
= k[0] * dr2do + k[1] * dr4do + k[4] * dr6do;
|
|
||||||
double dicdist2_do = -icdist2 * icdist2
|
|
||||||
* ( k[5] * dr2do + k[6] * dr4do + k[7] * dr6do );
|
|
||||||
double dxd0_do = cdist * icdist2 * dxdo[j]
|
|
||||||
+ x * icdist2 * dcdist_do + x * cdist * dicdist2_do
|
|
||||||
+ k[2] * da1do + k[3] * da2do + k[8] * dr2do
|
|
||||||
+ k[9] * dr4do;
|
|
||||||
double dyd0_do = cdist * icdist2 * dydo[j]
|
|
||||||
+ y * icdist2 * dcdist_do + y * cdist * dicdist2_do
|
|
||||||
+ k[2] * da3do + k[3] * da1do + k[10] * dr2do
|
|
||||||
+ k[11] * dr4do;
|
|
||||||
dXdYd = dMatTilt * Vec2d( dxd0_do, dyd0_do );
|
|
||||||
dpdo_p[i * 3 + j] = fx * dXdYd( 0 );
|
|
||||||
dpdo_p[dpdo_step + i * 3 + j] = fy * dXdYd( 1 );
|
|
||||||
}
|
|
||||||
dpdo_p += dpdo_step * 2;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if( _m != imagePoints )
|
|
||||||
cvConvert( _m, imagePoints );
|
|
||||||
|
|
||||||
if( _dpdr != dpdr )
|
|
||||||
cvConvert( _dpdr, dpdr );
|
|
||||||
|
|
||||||
if( _dpdt != dpdt )
|
|
||||||
cvConvert( _dpdt, dpdt );
|
|
||||||
|
|
||||||
if( _dpdf != dpdf )
|
|
||||||
cvConvert( _dpdf, dpdf );
|
|
||||||
|
|
||||||
if( _dpdc != dpdc )
|
|
||||||
cvConvert( _dpdc, dpdc );
|
|
||||||
|
|
||||||
if( _dpdk != dpdk )
|
|
||||||
cvConvert( _dpdk, dpdk );
|
|
||||||
|
|
||||||
if( _dpdo != dpdo )
|
|
||||||
cvConvert( _dpdo, dpdo );
|
|
||||||
}
|
|
||||||
|
|
||||||
static void _cvProjectPoints2( const CvMat* objectPoints,
|
|
||||||
const CvMat* r_vec,
|
|
||||||
const CvMat* t_vec,
|
|
||||||
const CvMat* A,
|
|
||||||
const CvMat* distCoeffs,
|
|
||||||
CvMat* imagePoints, CvMat* dpdr,
|
|
||||||
CvMat* dpdt, CvMat* dpdf,
|
|
||||||
CvMat* dpdc, CvMat* dpdk,
|
|
||||||
double aspectRatio )
|
|
||||||
{
|
|
||||||
_cvProjectPoints2Internal( objectPoints, r_vec, t_vec, A, distCoeffs, imagePoints, dpdr, dpdt,
|
|
||||||
dpdf, dpdc, dpdk, NULL, aspectRatio );
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -13,7 +13,7 @@
|
|||||||
Generate map file for aruco_map nodelet.
|
Generate map file for aruco_map nodelet.
|
||||||
|
|
||||||
Usage:
|
Usage:
|
||||||
genmap.py <length> <x> <y> <dist_x> <dist_y> [<first>] [<x0>] [<y0>] [--top-left | --bottom-left]
|
genmap.py <length> <x> <y> <dist_x> <dist_y> [<first>] [<x0>] [<y0>] [--top-left | --bottom-left] [-o <filename>]
|
||||||
genmap.py (-h | --help)
|
genmap.py (-h | --help)
|
||||||
|
|
||||||
Options:
|
Options:
|
||||||
@@ -27,6 +27,7 @@ Options:
|
|||||||
<y0> Y coordinate for the first marker [default: 0]
|
<y0> Y coordinate for the first marker [default: 0]
|
||||||
--top-left First marker is on top-left (default)
|
--top-left First marker is on top-left (default)
|
||||||
--bottom-left First marker is on bottom-left
|
--bottom-left First marker is on bottom-left
|
||||||
|
-o <filename> Output map file name in the 'map' subdirectory of aruco_pose package
|
||||||
|
|
||||||
Example:
|
Example:
|
||||||
rosrun aruco_pose genmap.py 0.33 2 4 1 1 0 > $(catkin_find aruco_pose map)/test_map.txt
|
rosrun aruco_pose genmap.py 0.33 2 4 1 1 0 > $(catkin_find aruco_pose map)/test_map.txt
|
||||||
@@ -34,6 +35,8 @@ Example:
|
|||||||
|
|
||||||
from __future__ import print_function
|
from __future__ import print_function
|
||||||
|
|
||||||
|
import sys
|
||||||
|
from os import path
|
||||||
from docopt import docopt
|
from docopt import docopt
|
||||||
|
|
||||||
|
|
||||||
@@ -49,14 +52,19 @@ dist_x = float(arguments['<dist_x>'])
|
|||||||
dist_y = float(arguments['<dist_y>'])
|
dist_y = float(arguments['<dist_y>'])
|
||||||
bottom_left = arguments['--bottom-left']
|
bottom_left = arguments['--bottom-left']
|
||||||
|
|
||||||
|
if arguments['-o'] is None:
|
||||||
|
output = sys.stdout
|
||||||
|
else:
|
||||||
|
output = open(path.join(path.dirname(__file__), '..', 'map', arguments['-o']), 'w')
|
||||||
|
|
||||||
max_y = y0 + (markers_y - 1) * dist_y
|
max_y = y0 + (markers_y - 1) * dist_y
|
||||||
|
|
||||||
print('# id\tlength\tx\ty\tz\trot_z\trot_y\trot_x')
|
output.write('# id\tlength\tx\ty\tz\trot_z\trot_y\trot_x\n')
|
||||||
for y in range(markers_y):
|
for y in range(markers_y):
|
||||||
for x in range(markers_x):
|
for x in range(markers_x):
|
||||||
pos_x = x0 + x * dist_x
|
pos_x = x0 + x * dist_x
|
||||||
pos_y = y0 + y * dist_y
|
pos_y = y0 + y * dist_y
|
||||||
if not bottom_left:
|
if not bottom_left:
|
||||||
pos_y = max_y - pos_y
|
pos_y = max_y - pos_y
|
||||||
print('{}\t{}\t{}\t{}\t{}\t{}\t{}\t{}'.format(first, length, pos_x, pos_y, 0, 0, 0, 0))
|
output.write('{}\t{}\t{}\t{}\t{}\t{}\t{}\t{}\n'.format(first, length, pos_x, pos_y, 0, 0, 0, 0))
|
||||||
first += 1
|
first += 1
|
||||||
|
|||||||
@@ -1,4 +1,4 @@
|
|||||||
#!/usr/bin/env python
|
#!/usr/bin/env python3
|
||||||
|
|
||||||
from distutils.core import setup
|
from distutils.core import setup
|
||||||
|
|
||||||
|
|||||||
@@ -1,4 +1,4 @@
|
|||||||
# Information: https://clover.coex.tech/aruco
|
# Information: https://clover.coex.tech/en/aruco.html
|
||||||
|
|
||||||
import rospy
|
import rospy
|
||||||
from clover import srv
|
from clover import srv
|
||||||
|
|||||||
@@ -1,11 +0,0 @@
|
|||||||
# Information: https://clover.coex.tech/en/simple_offboard.html#gettelemetry
|
|
||||||
|
|
||||||
import rospy
|
|
||||||
from clover import srv
|
|
||||||
|
|
||||||
rospy.init_node('flight')
|
|
||||||
|
|
||||||
get_telemetry = rospy.ServiceProxy('get_telemetry', srv.GetTelemetry)
|
|
||||||
|
|
||||||
# Print drone's state
|
|
||||||
print(get_telemetry())
|
|
||||||
@@ -1,4 +1,4 @@
|
|||||||
# Information: https://clover.coex.tech/led
|
# Information: https://clover.coex.tech/en/leds.html
|
||||||
|
|
||||||
import rospy
|
import rospy
|
||||||
from clover.srv import SetLEDEffect
|
from clover.srv import SetLEDEffect
|
||||||
@@ -7,25 +7,19 @@ rospy.init_node('leds')
|
|||||||
|
|
||||||
set_effect = rospy.ServiceProxy('led/set_effect', SetLEDEffect) # define proxy to ROS-service
|
set_effect = rospy.ServiceProxy('led/set_effect', SetLEDEffect) # define proxy to ROS-service
|
||||||
|
|
||||||
print('Fill red')
|
|
||||||
set_effect(r=255, g=0, b=0) # fill strip with red color
|
set_effect(r=255, g=0, b=0) # fill strip with red color
|
||||||
rospy.sleep(2)
|
rospy.sleep(2)
|
||||||
|
|
||||||
print('Fill green')
|
|
||||||
set_effect(r=0, g=100, b=0) # fill strip with green color
|
set_effect(r=0, g=100, b=0) # fill strip with green color
|
||||||
rospy.sleep(2)
|
rospy.sleep(2)
|
||||||
|
|
||||||
print('Fade to blue')
|
|
||||||
set_effect(effect='fade', r=0, g=0, b=255) # fade to blue color
|
set_effect(effect='fade', r=0, g=0, b=255) # fade to blue color
|
||||||
rospy.sleep(2)
|
rospy.sleep(2)
|
||||||
|
|
||||||
print('Flash red')
|
|
||||||
set_effect(effect='flash', r=255, g=0, b=0) # flash twice with red color
|
set_effect(effect='flash', r=255, g=0, b=0) # flash twice with red color
|
||||||
rospy.sleep(2)
|
rospy.sleep(5)
|
||||||
|
|
||||||
print('Blink white')
|
|
||||||
set_effect(effect='blink', r=255, g=255, b=255) # blink with white color
|
set_effect(effect='blink', r=255, g=255, b=255) # blink with white color
|
||||||
rospy.sleep(5)
|
rospy.sleep(5)
|
||||||
|
|
||||||
print('Rainbow')
|
|
||||||
set_effect(effect='rainbow') # show rainbow
|
set_effect(effect='rainbow') # show rainbow
|
||||||
|
|||||||
@@ -65,7 +65,7 @@ echo_stamp "#6 Turn on UART"
|
|||||||
# https://github.com/RPi-Distro/raspi-config/pull/75
|
# https://github.com/RPi-Distro/raspi-config/pull/75
|
||||||
/usr/bin/raspi-config nonint do_serial 1
|
/usr/bin/raspi-config nonint do_serial 1
|
||||||
/usr/bin/raspi-config nonint set_config_var enable_uart 1 /boot/config.txt
|
/usr/bin/raspi-config nonint set_config_var enable_uart 1 /boot/config.txt
|
||||||
echo dtoverlay=pi3-disable-bt >> /boot/config.txt
|
/usr/bin/raspi-config nonint set_config_var dtoverlay pi3-disable-bt /boot/config.txt
|
||||||
systemctl disable hciuart.service
|
systemctl disable hciuart.service
|
||||||
|
|
||||||
# After adding to Raspbian OS
|
# After adding to Raspbian OS
|
||||||
|
|||||||
18
builder/assets/noetic-rosdep-clover.yaml
Normal file
@@ -0,0 +1,18 @@
|
|||||||
|
async_web_server_cpp:
|
||||||
|
debian:
|
||||||
|
buster: [ros-noetic-async-web-server-cpp]
|
||||||
|
led_msgs:
|
||||||
|
debian:
|
||||||
|
buster: [ros-noetic-led-msgs]
|
||||||
|
ros_pytest:
|
||||||
|
debian:
|
||||||
|
buster: [ros-noetic-ros-pytest]
|
||||||
|
tf2_web_republisher:
|
||||||
|
debian:
|
||||||
|
buster: [ros-noetic-tf2-web-republisher]
|
||||||
|
web_video_server:
|
||||||
|
debian:
|
||||||
|
buster: [ros-noetic-web-video-server]
|
||||||
|
ws281x:
|
||||||
|
debian:
|
||||||
|
buster: [ros-noetic-ws281x]
|
||||||
@@ -3,7 +3,7 @@ Description=Launcher for the ROS master, parameter server and rosout logging nod
|
|||||||
|
|
||||||
[Service]
|
[Service]
|
||||||
User=pi
|
User=pi
|
||||||
ExecStart=/bin/sh -c ". /opt/ros/melodic/setup.sh; ROS_HOSTNAME=`hostname`.local exec roscore"
|
ExecStart=/bin/sh -c ". /opt/ros/noetic/setup.sh; ROS_HOSTNAME=`hostname`.local exec roscore"
|
||||||
Restart=on-failure
|
Restart=on-failure
|
||||||
RestartSec=3
|
RestartSec=3
|
||||||
|
|
||||||
|
|||||||
@@ -15,7 +15,7 @@
|
|||||||
|
|
||||||
set -e # Exit immidiately on non-zero result
|
set -e # Exit immidiately on non-zero result
|
||||||
|
|
||||||
SOURCE_IMAGE="https://downloads.raspberrypi.org/raspios_lite_armhf/images/raspios_lite_armhf-2021-01-12/2021-01-11-raspios-buster-armhf-lite.zip"
|
SOURCE_IMAGE="https://downloads.raspberrypi.org/raspios_lite_arm64/images/raspios_lite_arm64-2020-08-24/2020-08-20-raspios-buster-arm64-lite.zip"
|
||||||
|
|
||||||
export DEBIAN_FRONTEND=${DEBIAN_FRONTEND:='noninteractive'}
|
export DEBIAN_FRONTEND=${DEBIAN_FRONTEND:='noninteractive'}
|
||||||
export LANG=${LANG:='C.UTF-8'}
|
export LANG=${LANG:='C.UTF-8'}
|
||||||
@@ -105,7 +105,7 @@ ${BUILDER_DIR}/image-chroot.sh ${IMAGE_PATH} copy ${SCRIPTS_DIR}'/assets/monkey.
|
|||||||
# 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'
|
||||||
# examples
|
# examples
|
||||||
${BUILDER_DIR}/image-chroot.sh ${IMAGE_PATH} copy ${SCRIPTS_DIR}'/assets/examples' '/home/pi/' # TODO: symlink?
|
${BUILDER_DIR}/image-chroot.sh ${IMAGE_PATH} copy ${SCRIPTS_DIR}'/assets/examples' '/home/pi/'
|
||||||
# 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
|
||||||
@@ -116,7 +116,7 @@ ${BUILDER_DIR}/image-chroot.sh ${IMAGE_PATH} copy ${SCRIPTS_DIR}'/assets/avahi-s
|
|||||||
# Clover
|
# Clover
|
||||||
${BUILDER_DIR}/image-chroot.sh ${IMAGE_PATH} copy ${SCRIPTS_DIR}'/assets/clover.service' '/lib/systemd/system/'
|
${BUILDER_DIR}/image-chroot.sh ${IMAGE_PATH} copy ${SCRIPTS_DIR}'/assets/clover.service' '/lib/systemd/system/'
|
||||||
${BUILDER_DIR}/image-chroot.sh ${IMAGE_PATH} copy ${SCRIPTS_DIR}'/assets/roscore.service' '/lib/systemd/system/'
|
${BUILDER_DIR}/image-chroot.sh ${IMAGE_PATH} copy ${SCRIPTS_DIR}'/assets/roscore.service' '/lib/systemd/system/'
|
||||||
${BUILDER_DIR}/image-chroot.sh ${IMAGE_PATH} copy ${SCRIPTS_DIR}'/assets/melodic-rosdep-clover.yaml' '/etc/ros/rosdep/'
|
${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/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/'
|
||||||
|
|||||||
@@ -55,7 +55,4 @@ echo_stamp "Set max space for syslogs"
|
|||||||
# https://unix.stackexchange.com/questions/139513/how-to-clear-journalctl
|
# https://unix.stackexchange.com/questions/139513/how-to-clear-journalctl
|
||||||
sed -i 's/#SystemMaxUse=/SystemMaxUse=200M/' /etc/systemd/journald.conf
|
sed -i 's/#SystemMaxUse=/SystemMaxUse=200M/' /etc/systemd/journald.conf
|
||||||
|
|
||||||
echo_stamp "Move /etc/ld.so.preload out of the way"
|
|
||||||
mv /etc/ld.so.preload /etc/ld.so.preload.disabled-for-build
|
|
||||||
|
|
||||||
echo_stamp "End of init image"
|
echo_stamp "End of init image"
|
||||||
|
|||||||
@@ -21,6 +21,9 @@ INSTALL_ROS_PACK_SOURCES=$3
|
|||||||
DISCOVER_ROS_PACK=$4
|
DISCOVER_ROS_PACK=$4
|
||||||
NUMBER_THREADS=$5
|
NUMBER_THREADS=$5
|
||||||
|
|
||||||
|
# Current ROS distribution
|
||||||
|
ROS_DISTRO=noetic
|
||||||
|
|
||||||
echo_stamp() {
|
echo_stamp() {
|
||||||
# TEMPLATE: echo_stamp <TEXT> <TYPE>
|
# TEMPLATE: echo_stamp <TEXT> <TYPE>
|
||||||
# TYPE: SUCCESS, ERROR, INFO
|
# TYPE: SUCCESS, ERROR, INFO
|
||||||
@@ -68,7 +71,8 @@ my_travis_retry() {
|
|||||||
# TODO: 'kinetic-rosdep-clover.yaml' should add only if we use our repo?
|
# TODO: 'kinetic-rosdep-clover.yaml' should add only if we use our repo?
|
||||||
echo_stamp "Init rosdep"
|
echo_stamp "Init rosdep"
|
||||||
my_travis_retry rosdep init
|
my_travis_retry rosdep init
|
||||||
echo "yaml file:///etc/ros/rosdep/melodic-rosdep-clover.yaml" >> /etc/ros/rosdep/sources.list.d/20-default.list
|
# FIXME: Re-add this after missing packages are built
|
||||||
|
echo "yaml file:///etc/ros/rosdep/${ROS_DISTRO}-rosdep-clover.yaml" >> /etc/ros/rosdep/sources.list.d/20-default.list
|
||||||
my_travis_retry rosdep update
|
my_travis_retry rosdep update
|
||||||
|
|
||||||
echo_stamp "Populate rosdep for ROS user"
|
echo_stamp "Populate rosdep for ROS user"
|
||||||
@@ -76,20 +80,34 @@ my_travis_retry sudo -u pi rosdep update
|
|||||||
|
|
||||||
export ROS_IP='127.0.0.1' # needed for running tests
|
export ROS_IP='127.0.0.1' # needed for running tests
|
||||||
|
|
||||||
# echo_stamp "Reconfiguring Clover repository for simplier unshallowing" # TODO: bring back
|
echo_stamp "Reconfiguring Clover repository for simplier unshallowing"
|
||||||
# cd /home/pi/catkin_ws/src/clover
|
cd /home/pi/catkin_ws/src/clover
|
||||||
# git config remote.origin.fetch "+refs/heads/*:refs/remotes/origin/*"
|
git config remote.origin.fetch "+refs/heads/*:refs/remotes/origin/*"
|
||||||
echo_stamp "Remove .git from Clover to reduce the size"
|
|
||||||
rm -rf /home/pi/catkin_ws/src/clover/.git # TODO: remove
|
# This is sort of a hack to force "custom" packages to be installed - the ones built by COEX, linked against OpenCV 4.2
|
||||||
|
# I **wish** OpenCV would not be such a mess, but, well, here we are.
|
||||||
|
echo_stamp "Installing OpenCV 4.2-compatible ROS packages"
|
||||||
|
apt install -y --no-install-recommends \
|
||||||
|
ros-${ROS_DISTRO}-compressed-image-transport=1.14.0-0buster \
|
||||||
|
ros-${ROS_DISTRO}-cv-bridge=1.15.0-0buster \
|
||||||
|
ros-${ROS_DISTRO}-cv-camera=0.5.0-0buster \
|
||||||
|
ros-${ROS_DISTRO}-image-publisher=1.15.2-0buster \
|
||||||
|
ros-${ROS_DISTRO}-web-video-server=0.2.1-0buster
|
||||||
|
apt-mark hold \
|
||||||
|
ros-${ROS_DISTRO}-compressed-image-transport \
|
||||||
|
ros-${ROS_DISTRO}-cv-bridge \
|
||||||
|
ros-${ROS_DISTRO}-cv-camera \
|
||||||
|
ros-${ROS_DISTRO}-image-publisher \
|
||||||
|
ros-${ROS_DISTRO}-web-video-server
|
||||||
|
|
||||||
echo_stamp "Build and install Clover"
|
echo_stamp "Build and install Clover"
|
||||||
cd /home/pi/catkin_ws
|
cd /home/pi/catkin_ws
|
||||||
# Don't try to install gazebo_ros
|
# Don't try to install gazebo_ros
|
||||||
my_travis_retry rosdep install -y --from-paths src --ignore-src --rosdistro melodic --os=debian:buster \
|
my_travis_retry rosdep install -y --from-paths src --ignore-src --rosdistro ${ROS_DISTRO} --os=debian:buster \
|
||||||
--skip-keys=gazebo_ros --skip-keys=gazebo_plugins
|
--skip-keys=gazebo_ros --skip-keys=gazebo_plugins
|
||||||
my_travis_retry pip install wheel
|
my_travis_retry pip3 install wheel
|
||||||
my_travis_retry pip install -r /home/pi/catkin_ws/src/clover/clover/requirements.txt
|
my_travis_retry pip3 install -r /home/pi/catkin_ws/src/clover/clover/requirements.txt
|
||||||
source /opt/ros/melodic/setup.bash
|
source /opt/ros/${ROS_DISTRO}/setup.bash
|
||||||
# Don't build simulation plugins for actual drone
|
# Don't build simulation plugins for actual drone
|
||||||
catkin_make -j2 -DCMAKE_BUILD_TYPE=Release -DCATKIN_BLACKLIST_PACKAGES=clover_gazebo_plugins
|
catkin_make -j2 -DCMAKE_BUILD_TYPE=Release -DCATKIN_BLACKLIST_PACKAGES=clover_gazebo_plugins
|
||||||
|
|
||||||
@@ -101,30 +119,24 @@ rm -rf build # remove build artifacts
|
|||||||
echo_stamp "Build Clover documentation"
|
echo_stamp "Build Clover documentation"
|
||||||
cd /home/pi/catkin_ws/src/clover
|
cd /home/pi/catkin_ws/src/clover
|
||||||
NPM_CONFIG_UNSAFE_PERM=true npm install gitbook-cli -g
|
NPM_CONFIG_UNSAFE_PERM=true npm install gitbook-cli -g
|
||||||
NPM_CONFIG_UNSAFE_PERM=true gitbook fetch 3.2.3 && npm i npm@3.10.10 --prefix=~/.gitbook/versions/3.2.3/ # fixing https://travis-ci.org/github/CopterExpress/clover/jobs/766541125#L932
|
|
||||||
NPM_CONFIG_UNSAFE_PERM=true gitbook install
|
NPM_CONFIG_UNSAFE_PERM=true gitbook install
|
||||||
gitbook build
|
gitbook build
|
||||||
touch node_modules/CATKIN_IGNORE docs/CATKIN_IGNORE _book/CATKIN_IGNORE clover/www/CATKIN_IGNORE apps/CATKIN_IGNORE # ignore documentation files by catkin
|
touch node_modules/CATKIN_IGNORE docs/CATKIN_IGNORE _book/CATKIN_IGNORE clover/www/CATKIN_IGNORE apps/CATKIN_IGNORE # ignore documentation files by catkin
|
||||||
|
|
||||||
echo_stamp "Installing additional ROS packages"
|
echo_stamp "Installing additional ROS packages"
|
||||||
my_travis_retry apt-get install -y --no-install-recommends \
|
my_travis_retry apt-get install -y --no-install-recommends \
|
||||||
ros-melodic-dynamic-reconfigure \
|
ros-${ROS_DISTRO}-dynamic-reconfigure \
|
||||||
ros-melodic-compressed-image-transport \
|
ros-${ROS_DISTRO}-rosbridge-suite \
|
||||||
ros-melodic-rosbridge-suite \
|
ros-${ROS_DISTRO}-rosserial \
|
||||||
ros-melodic-rosserial \
|
ros-${ROS_DISTRO}-usb-cam \
|
||||||
ros-melodic-usb-cam \
|
ros-${ROS_DISTRO}-vl53l1x \
|
||||||
ros-melodic-vl53l1x \
|
ros-${ROS_DISTRO}-ws281x \
|
||||||
ros-melodic-ws281x \
|
ros-${ROS_DISTRO}-rosshow
|
||||||
ros-melodic-rosshow
|
|
||||||
|
|
||||||
# TODO move GeographicLib datasets to Mavros debian package
|
# TODO move GeographicLib datasets to Mavros debian package
|
||||||
echo_stamp "Install GeographicLib datasets (needed for mavros)" \
|
echo_stamp "Install GeographicLib datasets (needed for mavros)" \
|
||||||
&& wget -qO- https://raw.githubusercontent.com/mavlink/mavros/master/mavros/scripts/install_geographiclib_datasets.sh | bash
|
&& wget -qO- https://raw.githubusercontent.com/mavlink/mavros/master/mavros/scripts/install_geographiclib_datasets.sh | bash
|
||||||
|
|
||||||
# FIXME: Buster comes with tornado==5.1.1 but we need tornado==4.2.1 for rosbridge_suite
|
|
||||||
# (note that Python 3 will still have a more recent version)
|
|
||||||
pip install tornado==4.2.1
|
|
||||||
|
|
||||||
echo_stamp "Running tests"
|
echo_stamp "Running tests"
|
||||||
cd /home/pi/catkin_ws
|
cd /home/pi/catkin_ws
|
||||||
# FIXME: Investigate failing tests
|
# FIXME: Investigate failing tests
|
||||||
@@ -133,15 +145,12 @@ 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 "Change permissions for examples"
|
|
||||||
chown -Rf pi:pi /home/pi/examples
|
|
||||||
|
|
||||||
echo_stamp "Setup ROS environment"
|
echo_stamp "Setup ROS environment"
|
||||||
cat << EOF >> /home/pi/.bashrc
|
cat << EOF >> /home/pi/.bashrc
|
||||||
LANG='C.UTF-8'
|
LANG='C.UTF-8'
|
||||||
LC_ALL='C.UTF-8'
|
LC_ALL='C.UTF-8'
|
||||||
export ROS_HOSTNAME=\`hostname\`.local
|
export ROS_HOSTNAME=\`hostname\`.local
|
||||||
source /opt/ros/melodic/setup.bash
|
source /opt/ros/${ROS_DISTRO}/setup.bash
|
||||||
source /home/pi/catkin_ws/devel/setup.bash
|
source /home/pi/catkin_ws/devel/setup.bash
|
||||||
EOF
|
EOF
|
||||||
|
|
||||||
|
|||||||
@@ -70,8 +70,8 @@ apt-get update \
|
|||||||
&& apt-key adv --keyserver hkp://keyserver.ubuntu.com:80 --recv-key C1CF6E31E6BADE8868B172B4F42ED6FBAB17C654
|
&& apt-key adv --keyserver hkp://keyserver.ubuntu.com:80 --recv-key C1CF6E31E6BADE8868B172B4F42ED6FBAB17C654
|
||||||
|
|
||||||
echo "deb http://packages.ros.org/ros/ubuntu buster main" > /etc/apt/sources.list.d/ros-latest.list
|
echo "deb http://packages.ros.org/ros/ubuntu buster main" > /etc/apt/sources.list.d/ros-latest.list
|
||||||
echo "deb http://deb.coex.tech/opencv3 buster main" > /etc/apt/sources.list.d/opencv3.list
|
echo "deb http://deb.coex.tech/opencv4 buster main" > /etc/apt/sources.list.d/opencv3.list
|
||||||
echo "deb http://deb.coex.tech/rpi-ros-melodic buster main" > /etc/apt/sources.list.d/rpi-ros-melodic.list
|
echo "deb http://deb.coex.tech/ros buster main" > /etc/apt/sources.list.d/rpi-ros-melodic.list
|
||||||
echo "deb http://deb.coex.tech/clover buster main" > /etc/apt/sources.list.d/clover.list
|
echo "deb http://deb.coex.tech/clover buster main" > /etc/apt/sources.list.d/clover.list
|
||||||
|
|
||||||
echo_stamp "Update apt cache"
|
echo_stamp "Update apt cache"
|
||||||
@@ -82,7 +82,6 @@ apt-get update
|
|||||||
|
|
||||||
# Let's retry fetching those packages several times, just in case
|
# Let's retry fetching those packages several times, just in case
|
||||||
echo_stamp "Software installing"
|
echo_stamp "Software installing"
|
||||||
my_travis_retry apt-get install --no-install-recommends -y cmake-data=3.13.4-1 cmake=3.13.4-1 # FIXME: using older CMake due to https://travis-ci.org/github/CopterExpress/clover/jobs/764367665#L6984
|
|
||||||
my_travis_retry apt-get install --no-install-recommends -y \
|
my_travis_retry apt-get install --no-install-recommends -y \
|
||||||
unzip \
|
unzip \
|
||||||
zip \
|
zip \
|
||||||
@@ -95,22 +94,21 @@ lsof \
|
|||||||
git \
|
git \
|
||||||
dnsmasq \
|
dnsmasq \
|
||||||
tmux \
|
tmux \
|
||||||
tree \
|
|
||||||
vim \
|
vim \
|
||||||
libjpeg8 \
|
cmake \
|
||||||
tcpdump \
|
tcpdump \
|
||||||
ltrace \
|
|
||||||
libpoco-dev \
|
libpoco-dev \
|
||||||
libzbar0 \
|
libzbar0 \
|
||||||
python-rosdep \
|
python3-rosdep \
|
||||||
python-rosinstall-generator \
|
python3-rosinstall-generator \
|
||||||
python-wstool \
|
python3-wstool \
|
||||||
python-rosinstall \
|
python3-rosinstall \
|
||||||
build-essential \
|
build-essential \
|
||||||
libffi-dev \
|
libffi-dev \
|
||||||
monkey \
|
monkey \
|
||||||
pigpio python-pigpio python3-pigpio \
|
pigpio python-pigpio python3-pigpio \
|
||||||
i2c-tools \
|
i2c-tools \
|
||||||
|
espeak espeak-data python-espeak python3-espeak \
|
||||||
ntpdate \
|
ntpdate \
|
||||||
python-dev \
|
python-dev \
|
||||||
python3-dev \
|
python3-dev \
|
||||||
@@ -124,10 +122,9 @@ sed -i "s/updates_available//" /usr/share/byobu/status/status
|
|||||||
|
|
||||||
echo_stamp "Installing pip"
|
echo_stamp "Installing pip"
|
||||||
curl https://bootstrap.pypa.io/get-pip.py -o get-pip.py
|
curl https://bootstrap.pypa.io/get-pip.py -o get-pip.py
|
||||||
curl https://bootstrap.pypa.io/pip/2.7/get-pip.py -o get-pip2.py
|
|
||||||
python3 get-pip.py
|
python3 get-pip.py
|
||||||
python get-pip2.py
|
python get-pip.py
|
||||||
rm get-pip.py get-pip2.py
|
rm get-pip.py
|
||||||
#my_travis_retry pip install --upgrade pip
|
#my_travis_retry pip install --upgrade pip
|
||||||
#my_travis_retry pip3 install --upgrade pip
|
#my_travis_retry pip3 install --upgrade pip
|
||||||
|
|
||||||
@@ -137,28 +134,26 @@ pip3 --version
|
|||||||
|
|
||||||
echo_stamp "Install and enable Butterfly (web terminal)"
|
echo_stamp "Install and enable Butterfly (web terminal)"
|
||||||
echo_stamp "Workaround for tornado >= 6.0 breaking butterfly"
|
echo_stamp "Workaround for tornado >= 6.0 breaking butterfly"
|
||||||
export CRYPTOGRAPHY_DONT_BUILD_RUST=1
|
|
||||||
my_travis_retry pip3 install tornado==5.1.1
|
my_travis_retry pip3 install tornado==5.1.1
|
||||||
my_travis_retry pip3 install butterfly
|
my_travis_retry pip3 install butterfly
|
||||||
my_travis_retry pip3 install butterfly[systemd]
|
my_travis_retry pip3 install butterfly[systemd]
|
||||||
systemctl enable butterfly.socket
|
systemctl enable butterfly.socket
|
||||||
|
|
||||||
echo_stamp "Install ws281x library"
|
echo_stamp "Install ws281x library"
|
||||||
my_travis_retry pip install --prefer-binary rpi_ws281x
|
my_travis_retry pip3 install --prefer-binary rpi_ws281x
|
||||||
|
|
||||||
echo_stamp "Setup Monkey"
|
echo_stamp "Setup Monkey"
|
||||||
mv /etc/monkey/sites/default /etc/monkey/sites/default.orig
|
mv /etc/monkey/sites/default /etc/monkey/sites/default.orig
|
||||||
mv /root/monkey /etc/monkey/sites/default
|
mv /root/monkey /etc/monkey/sites/default
|
||||||
sed -i 's/SymLink Off/SymLink On/' /etc/monkey/monkey.conf
|
|
||||||
systemctl enable monkey.service
|
systemctl enable monkey.service
|
||||||
|
|
||||||
echo_stamp "Install Node.js"
|
echo_stamp "Install Node.js"
|
||||||
cd /home/pi
|
cd /home/pi
|
||||||
wget https://nodejs.org/dist/v10.15.0/node-v10.15.0-linux-armv6l.tar.gz
|
wget https://nodejs.org/dist/v10.15.0/node-v10.15.0-linux-arm64.tar.gz
|
||||||
tar -xzf node-v10.15.0-linux-armv6l.tar.gz
|
tar -xzf node-v10.15.0-linux-arm64.tar.gz
|
||||||
cp -R node-v10.15.0-linux-armv6l/* /usr/local/
|
cp -R node-v10.15.0-linux-arm64/* /usr/local/
|
||||||
rm -rf node-v10.15.0-linux-armv6l/
|
rm -rf node-v10.15.0-linux-arm64/
|
||||||
rm node-v10.15.0-linux-armv6l.tar.gz
|
rm node-v10.15.0-linux-arm64.tar.gz
|
||||||
|
|
||||||
echo_stamp "Installing ptvsd"
|
echo_stamp "Installing ptvsd"
|
||||||
my_travis_retry pip install ptvsd
|
my_travis_retry pip install ptvsd
|
||||||
|
|||||||
@@ -16,9 +16,9 @@ set -ex
|
|||||||
|
|
||||||
echo "Run image tests"
|
echo "Run image tests"
|
||||||
|
|
||||||
export ROS_DISTRO='melodic'
|
export ROS_DISTRO='noetic'
|
||||||
export ROS_IP='127.0.0.1'
|
export ROS_IP='127.0.0.1'
|
||||||
source /opt/ros/melodic/setup.bash
|
source /opt/ros/${ROS_DISTRO}/setup.bash
|
||||||
source /home/pi/catkin_ws/devel/setup.bash
|
source /home/pi/catkin_ws/devel/setup.bash
|
||||||
|
|
||||||
cd /home/pi/catkin_ws/src/clover/builder/test/
|
cd /home/pi/catkin_ws/src/clover/builder/test/
|
||||||
@@ -26,6 +26,3 @@ cd /home/pi/catkin_ws/src/clover/builder/test/
|
|||||||
./tests.py
|
./tests.py
|
||||||
./tests_py3.py
|
./tests_py3.py
|
||||||
[[ $(./tests_clever.py) == "Warning: clever package is renamed to clover" ]] # test backwards compatibility
|
[[ $(./tests_clever.py) == "Warning: clever package is renamed to clover" ]] # test backwards compatibility
|
||||||
|
|
||||||
echo "Move /etc/ld.so.preload back to its original position"
|
|
||||||
mv /etc/ld.so.preload.disabled-for-build /etc/ld.so.preload
|
|
||||||
|
|||||||
@@ -5,21 +5,40 @@ set -e
|
|||||||
# Step 1: Install pip
|
# Step 1: Install pip
|
||||||
apt update
|
apt update
|
||||||
apt install -y curl
|
apt install -y curl
|
||||||
curl https://bootstrap.pypa.io/pip/2.7/get-pip.py -o get-pip.py
|
curl https://bootstrap.pypa.io/get-pip.py -o get-pip.py
|
||||||
python ./get-pip.py
|
if [ "x${ROS_PYTHON_VERSION}" = "x3" ]; then
|
||||||
|
PYTHON=python3
|
||||||
|
else
|
||||||
|
PYTHON=python
|
||||||
|
fi
|
||||||
|
|
||||||
|
${PYTHON} ./get-pip.py
|
||||||
|
|
||||||
# Step 1.5: Add deb.coex.tech to apt
|
# Step 1.5: Add deb.coex.tech to apt
|
||||||
curl http://deb.coex.tech/aptly_repo_signing.key 2> /dev/null | apt-key add -
|
curl http://deb.coex.tech/aptly_repo_signing.key 2> /dev/null | apt-key add -
|
||||||
echo "deb http://deb.coex.tech/ros xenial main" > /etc/apt/sources.list.d/coex.tech.list
|
echo "deb http://deb.coex.tech/ros xenial main" > /etc/apt/sources.list.d/coex.tech.list
|
||||||
echo "yaml file:///etc/ros/rosdep/coex.yaml" > /etc/ros/rosdep/sources.list.d/99-coex.list
|
echo "yaml file:///etc/ros/rosdep/coex.yaml" > /etc/ros/rosdep/sources.list.d/99-coex.list
|
||||||
|
CODENAME=$(lsb_release -sc)
|
||||||
|
|
||||||
cat <<EOF > /etc/ros/rosdep/coex.yaml
|
cat <<EOF > /etc/ros/rosdep/coex.yaml
|
||||||
led_msgs:
|
led_msgs:
|
||||||
ubuntu:
|
ubuntu:
|
||||||
xenial: ros-kinetic-led-msgs
|
${CODENAME}: [ros-${ROS_DISTRO}-led-msgs]
|
||||||
bionic: ros-melodic-led-msgs
|
async_web_server_cpp:
|
||||||
debian:
|
ubuntu:
|
||||||
stretch: ros-kinetic-led-msgs
|
${CODENAME}: [ros-${ROS_DISTRO}-async-web-server-cpp]
|
||||||
buster: ros-melodic-led-msgs
|
ros_pytest:
|
||||||
|
ubuntu:
|
||||||
|
${CODENAME}: [ros-${ROS_DISTRO}-ros-pytest]
|
||||||
|
tf2_web_republisher:
|
||||||
|
ubuntu:
|
||||||
|
${CODENAME}: [ros-${ROS_DISTRO}-tf2-web-republisher]
|
||||||
|
web_video_server:
|
||||||
|
ubuntu:
|
||||||
|
${CODENAME}: [ros-${ROS_DISTRO}-web-video-server]
|
||||||
|
ws281x:
|
||||||
|
ubuntu:
|
||||||
|
${CODENAME}: [ros-${ROS_DISTRO}-ws281x]
|
||||||
EOF
|
EOF
|
||||||
apt update
|
apt update
|
||||||
rosdep update
|
rosdep update
|
||||||
@@ -37,10 +56,7 @@ cd /root/catkin_ws
|
|||||||
catkin_make
|
catkin_make
|
||||||
|
|
||||||
# Step 4: Run tests
|
# Step 4: Run tests
|
||||||
pip install --upgrade pytest
|
${PYTHON} -m pip install --upgrade pytest
|
||||||
cd /root/catkin_ws
|
cd /root/catkin_ws
|
||||||
source devel/setup.bash
|
source devel/setup.bash
|
||||||
catkin_make run_tests && catkin_test_results
|
catkin_make run_tests && catkin_test_results
|
||||||
|
|
||||||
# Step 5: Install packages
|
|
||||||
catkin_make install
|
|
||||||
|
|||||||
@@ -1,4 +1,4 @@
|
|||||||
#!/usr/bin/env python
|
#!/usr/bin/env python3
|
||||||
|
|
||||||
# validate all required modules installed
|
# validate all required modules installed
|
||||||
|
|
||||||
@@ -25,7 +25,7 @@ import pymavlink
|
|||||||
from pymavlink import mavutil
|
from pymavlink import mavutil
|
||||||
import rpi_ws281x
|
import rpi_ws281x
|
||||||
import pigpio
|
import pigpio
|
||||||
# from espeak import espeak
|
from espeak import espeak
|
||||||
from pyzbar import pyzbar
|
from pyzbar import pyzbar
|
||||||
|
|
||||||
print cv2.getBuildInformation()
|
print(cv2.getBuildInformation())
|
||||||
|
|||||||
@@ -32,7 +32,7 @@ monkey --version
|
|||||||
pigpiod -v
|
pigpiod -v
|
||||||
i2cdetect -V
|
i2cdetect -V
|
||||||
butterfly -h
|
butterfly -h
|
||||||
# espeak --version
|
espeak --version
|
||||||
mjpg_streamer --version
|
mjpg_streamer --version
|
||||||
|
|
||||||
# ros stuff
|
# ros stuff
|
||||||
@@ -43,8 +43,6 @@ rosversion aruco_pose
|
|||||||
rosversion vl53l1x
|
rosversion vl53l1x
|
||||||
rosversion mavros
|
rosversion mavros
|
||||||
rosversion mavros_extras
|
rosversion mavros_extras
|
||||||
rosversion ws281x
|
|
||||||
rosversion led_msgs
|
|
||||||
rosversion dynamic_reconfigure
|
rosversion dynamic_reconfigure
|
||||||
rosversion tf2_web_republisher
|
rosversion tf2_web_republisher
|
||||||
rosversion compressed_image_transport
|
rosversion compressed_image_transport
|
||||||
|
|||||||
@@ -1,4 +1,4 @@
|
|||||||
#!/usr/bin/env python
|
#!/usr/bin/env python3
|
||||||
|
|
||||||
# test backwards compatibility
|
# test backwards compatibility
|
||||||
|
|
||||||
|
|||||||
@@ -4,9 +4,7 @@ import os
|
|||||||
import sys
|
import sys
|
||||||
import subprocess
|
import subprocess
|
||||||
|
|
||||||
EXCLUDE = ('clever4-front-white.png', 'clever4-front-white-large.png', '.DS_Store',
|
EXCLUDE = ('clever4-front-white.png', '.DS_Store', 'clever4-front-black-large.png')
|
||||||
'clever4-front-black-large.png','clover42-black.png')
|
|
||||||
|
|
||||||
code = 0
|
code = 0
|
||||||
|
|
||||||
os.chdir('./docs')
|
os.chdir('./docs')
|
||||||
|
|||||||
@@ -1,8 +0,0 @@
|
|||||||
^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
|
||||||
Changelog for package clover
|
|
||||||
^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
|
||||||
|
|
||||||
0.21.1 (2020-11-17)
|
|
||||||
-------------------
|
|
||||||
* First release of clover package to ROS
|
|
||||||
* Contributors: Alexey Rogachevskiy, Arthur Golubtsov, Oleg Kalachev
|
|
||||||
@@ -30,7 +30,15 @@ list(APPEND CMAKE_MODULE_PATH "${CMAKE_CURRENT_LIST_DIR}/cmake")
|
|||||||
|
|
||||||
find_package(GeographicLib REQUIRED)
|
find_package(GeographicLib REQUIRED)
|
||||||
|
|
||||||
find_package(OpenCV 3 REQUIRED
|
# Workaround for OpenCV 3/4 support
|
||||||
|
set(_opencv_version 4)
|
||||||
|
find_package(OpenCV ${_opencv_version} QUIET)
|
||||||
|
if (NOT OpenCV_FOUND)
|
||||||
|
message(STATUS "Did not find OpenCV 4, searching for OpenCV 3")
|
||||||
|
set(_opencv_version 3)
|
||||||
|
endif()
|
||||||
|
|
||||||
|
find_package(OpenCV ${_opencv_version} REQUIRED
|
||||||
COMPONENTS
|
COMPONENTS
|
||||||
calib3d
|
calib3d
|
||||||
imgproc
|
imgproc
|
||||||
@@ -254,6 +262,10 @@ target_link_libraries(${PROJECT_NAME}
|
|||||||
# DESTINATION ${CATKIN_PACKAGE_SHARE_DESTINATION}
|
# DESTINATION ${CATKIN_PACKAGE_SHARE_DESTINATION}
|
||||||
# )
|
# )
|
||||||
|
|
||||||
|
catkin_install_python(PROGRAMS src/selfcheck.py
|
||||||
|
DESTINATION ${CATKIN_PACKAGE_BIN_DESTINATION}
|
||||||
|
)
|
||||||
|
|
||||||
# Only install udev rules when building a Debian package
|
# Only install udev rules when building a Debian package
|
||||||
# FIXME: Other operating systems may have other prefixes
|
# FIXME: Other operating systems may have other prefixes
|
||||||
string(FIND ${CMAKE_INSTALL_PREFIX} "/opt/ros" _PREFIX_INDEX)
|
string(FIND ${CMAKE_INSTALL_PREFIX} "/opt/ros" _PREFIX_INDEX)
|
||||||
|
|||||||
@@ -4,7 +4,7 @@ A bundle for autonomous navigation and drone control.
|
|||||||
|
|
||||||
## Manual installation
|
## Manual installation
|
||||||
|
|
||||||
Install ROS Melodic according to the [documentation](http://wiki.ros.org/melodic/Installation), then [create a Catkin workspace](http://wiki.ros.org/catkin/Tutorials/create_a_workspace).
|
Install ROS Noetic according to the [documentation](http://wiki.ros.org/noetic/Installation), then [create a Catkin workspace](http://wiki.ros.org/catkin/Tutorials/create_a_workspace).
|
||||||
|
|
||||||
Clone this repo to directory `~/catkin_ws/src/clover`:
|
Clone this repo to directory `~/catkin_ws/src/clover`:
|
||||||
|
|
||||||
@@ -44,12 +44,16 @@ Alternatively you may change the `fcu_url` property in `mavros.launch` file to p
|
|||||||
|
|
||||||
## Running
|
## Running
|
||||||
|
|
||||||
|
To start connection to SITL, use:
|
||||||
|
|
||||||
|
```bash
|
||||||
|
roslaunch clover sitl.launch
|
||||||
|
```
|
||||||
|
|
||||||
To start connection to the flight controller, use:
|
To start connection to the flight controller, use:
|
||||||
|
|
||||||
```bash
|
```bash
|
||||||
roslaunch clover clover.launch
|
roslaunch clover clover.launch
|
||||||
```
|
```
|
||||||
|
|
||||||
For the simulation information see the [corresponding article](https://clover.coex.tech/en/simulation.html).
|
|
||||||
|
|
||||||
> Note that the package is configured to connect to `/dev/px4fmu` by default (see [previous section](#manual-installation)). Install udev rules or specify path to your FCU device in `mavros.launch`.
|
> Note that the package is configured to connect to `/dev/px4fmu` by default (see [previous section](#manual-installation)). Install udev rules or specify path to your FCU device in `mavros.launch`.
|
||||||
|
|||||||
@@ -2,6 +2,9 @@
|
|||||||
<arg name="aruco_detect" default="true"/>
|
<arg name="aruco_detect" default="true"/>
|
||||||
<arg name="aruco_map" default="false"/>
|
<arg name="aruco_map" default="false"/>
|
||||||
<arg name="aruco_vpe" default="false"/>
|
<arg name="aruco_vpe" default="false"/>
|
||||||
|
<arg name="placement" default="floor"/> <!-- markers placement: floor, ceiling, unknown -->
|
||||||
|
<arg name="length" default="0.33"/> <!-- not-in-map markers length, m -->
|
||||||
|
<arg name="map" default="map.txt"/> <!-- markers map file name -->
|
||||||
|
|
||||||
<!-- For additional help go to https://clover.coex.tech/aruco -->
|
<!-- For additional help go to https://clover.coex.tech/aruco -->
|
||||||
|
|
||||||
@@ -12,11 +15,14 @@
|
|||||||
<remap from="map_markers" to="aruco_map/markers" if="$(arg aruco_map)"/>
|
<remap from="map_markers" to="aruco_map/markers" if="$(arg aruco_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="known_tilt" value="map"/>
|
<param name="known_tilt" value="map" if="$(eval placement == 'floor')"/>
|
||||||
<param name="length" value="0.33"/>
|
<param name="known_tilt" value="map_flipped" if="$(eval position == 'ceiling')"/>
|
||||||
|
<param name="length" value="$(arg length)"/>
|
||||||
<!-- aruco detector parameters -->
|
<!-- aruco detector parameters -->
|
||||||
<param name="cornerRefinementMethod" value="2"/> <!-- contour refinement -->
|
<param name="cornerRefinementMethod" value="2"/> <!-- contour refinement -->
|
||||||
<param name="minMarkerPerimeterRate" value="0.075"/> <!-- 0.075 for 320x240, 0.0375 for 640x480 -->
|
<param name="minMarkerPerimeterRate" value="0.075"/> <!-- 0.075 for 320x240, 0.0375 for 640x480 -->
|
||||||
|
<!-- length override example: -->
|
||||||
|
<!-- <param name="length_override/3" value="0.1"/> -->
|
||||||
</node>
|
</node>
|
||||||
|
|
||||||
<!-- aruco_map: estimate aruco map pose -->
|
<!-- aruco_map: estimate aruco map pose -->
|
||||||
@@ -24,8 +30,9 @@
|
|||||||
<remap from="image_raw" to="main_camera/image_raw"/>
|
<remap from="image_raw" to="main_camera/image_raw"/>
|
||||||
<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/map.txt"/>
|
<param name="map" value="$(find aruco_pose)/map/$(arg map)"/>
|
||||||
<param name="known_tilt" value="map"/>
|
<param name="known_tilt" value="map" if="$(eval placement == 'floor')"/>
|
||||||
|
<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)"/>
|
||||||
|
|||||||
@@ -11,7 +11,8 @@
|
|||||||
<arg name="rangefinder_vl53l1x" default="true"/>
|
<arg name="rangefinder_vl53l1x" default="true"/>
|
||||||
<arg name="led" default="true"/>
|
<arg name="led" default="true"/>
|
||||||
<arg name="blocks" default="false"/>
|
<arg name="blocks" default="false"/>
|
||||||
<arg name="rc" default="false"/>
|
<arg name="rc" default="true"/>
|
||||||
|
<arg name="shell" default="true"/>
|
||||||
|
|
||||||
<arg name="simulator" default="false"/> <!-- flag that we are operating on a simulated drone -->
|
<arg name="simulator" default="false"/> <!-- flag that we are operating on a simulated drone -->
|
||||||
|
|
||||||
@@ -90,6 +91,9 @@
|
|||||||
<param name="use_fake_gcs" value="false"/>
|
<param name="use_fake_gcs" value="false"/>
|
||||||
</node>
|
</node>
|
||||||
|
|
||||||
|
<!-- Shell access through ROS service -->
|
||||||
|
<node name="shell" pkg="clover" type="shell" output="screen" if="$(arg shell)"/>
|
||||||
|
|
||||||
<!-- Update static directory -->
|
<!-- Update static directory -->
|
||||||
<node pkg="roswww_static" name="roswww_static" type="main.py" clear_params="true">
|
<node pkg="roswww_static" name="roswww_static" type="main.py" clear_params="true">
|
||||||
<param name="default_package" value="clover"/>
|
<param name="default_package" value="clover"/>
|
||||||
|
|||||||
@@ -2,7 +2,7 @@
|
|||||||
<arg name="ws281x" default="true"/>
|
<arg name="ws281x" default="true"/>
|
||||||
<arg name="led_effect" default="true"/>
|
<arg name="led_effect" default="true"/>
|
||||||
<arg name="led_notify" default="true"/>
|
<arg name="led_notify" default="true"/>
|
||||||
<arg name="led_count" default="72"/>
|
<arg name="led_count" default="58"/>
|
||||||
<arg name="gpio_pin" default="21"/>
|
<arg name="gpio_pin" default="21"/>
|
||||||
|
|
||||||
<arg name="simulator" default="false"/>
|
<arg name="simulator" default="false"/>
|
||||||
|
|||||||
@@ -6,16 +6,13 @@
|
|||||||
<arg name="viz" default="true"/>
|
<arg name="viz" default="true"/>
|
||||||
<arg name="respawn" default="true"/>
|
<arg name="respawn" default="true"/>
|
||||||
<arg name="distance_sensor_remap" default="rangefinder/range"/>
|
<arg name="distance_sensor_remap" default="rangefinder/range"/>
|
||||||
<arg name="usb_device" default="/dev/px4fmu"/>
|
|
||||||
<arg name="prefix" default="" unless="$(eval fcu_conn == 'usb')"/>
|
|
||||||
<arg name="prefix" default="rosrun clover waitfile $(arg usb_device)" if="$(eval fcu_conn == 'usb')"/>
|
|
||||||
|
|
||||||
<node pkg="mavros" type="mavros_node" name="mavros" launch-prefix="$(arg prefix)" required="false" clear_params="true" respawn="$(arg respawn)" unless="$(eval fcu_conn == 'none')" respawn_delay="1" output="screen">
|
<node pkg="mavros" type="mavros_node" name="mavros" required="false" clear_params="true" respawn="$(arg respawn)" unless="$(eval fcu_conn == 'none')" respawn_delay="1" output="screen">
|
||||||
<!-- UART connection -->
|
<!-- UART connection -->
|
||||||
<param name="fcu_url" value="/dev/ttyAMA0:921600" if="$(eval fcu_conn is None or fcu_conn == 'uart')"/>
|
<param name="fcu_url" value="/dev/ttyAMA0:921600" if="$(eval fcu_conn is None or fcu_conn == 'uart')"/>
|
||||||
|
|
||||||
<!-- USB connection -->
|
<!-- USB connection -->
|
||||||
<param name="fcu_url" value="$(arg usb_device)" if="$(eval fcu_conn == 'usb')"/>
|
<param name="fcu_url" value="/dev/px4fmu" if="$(eval fcu_conn == 'usb')"/>
|
||||||
|
|
||||||
<!-- sitl before PX4 1.9.0 -->
|
<!-- sitl before PX4 1.9.0 -->
|
||||||
<param name="fcu_url" value="udp://@$(arg fcu_ip):14557" if="$(eval fcu_conn == 'udp')"/>
|
<param name="fcu_url" value="udp://@$(arg fcu_ip):14557" if="$(eval fcu_conn == 'udp')"/>
|
||||||
|
|||||||
19
clover/launch/sitl.launch
Normal file
@@ -0,0 +1,19 @@
|
|||||||
|
<launch>
|
||||||
|
<!-- clover configuration for testing in sitl -->
|
||||||
|
<arg name="ip" default="127.0.0.1"/>
|
||||||
|
<arg name="rosbridge" default="false"/>
|
||||||
|
|
||||||
|
<include file="$(find clover)/launch/clover.launch">
|
||||||
|
<arg name="fcu_conn" value="udp"/>
|
||||||
|
<arg name="fcu_ip" value="$(arg ip)"/>
|
||||||
|
<arg name="gcs_bridge" value="false"/>
|
||||||
|
<arg name="optical_flow" value="false"/>
|
||||||
|
<arg name="web_video_server" default="false"/>
|
||||||
|
<arg name="main_camera" default="false"/>
|
||||||
|
<arg name="rosbridge" value="$(arg rosbridge)"/>
|
||||||
|
<arg name="aruco" default="false"/>
|
||||||
|
<arg name="rangefinder_vl53l1x" default="false"/>
|
||||||
|
<arg name="led" default="false"/>
|
||||||
|
<arg name="rc" default="false"/>
|
||||||
|
</include>
|
||||||
|
</launch>
|
||||||
@@ -1,7 +1,7 @@
|
|||||||
<?xml version="1.0"?>
|
<?xml version="1.0"?>
|
||||||
<package format="2">
|
<package format="3">
|
||||||
<name>clover</name>
|
<name>clover</name>
|
||||||
<version>0.21.1</version>
|
<version>0.0.1</version>
|
||||||
<description>The Clover package</description>
|
<description>The Clover package</description>
|
||||||
|
|
||||||
<maintainer email="okalachev@gmail.com">Oleg Kalachev</maintainer>
|
<maintainer email="okalachev@gmail.com">Oleg Kalachev</maintainer>
|
||||||
@@ -37,7 +37,8 @@
|
|||||||
<depend>rosbridge_server</depend>
|
<depend>rosbridge_server</depend>
|
||||||
<depend>web_video_server</depend>
|
<depend>web_video_server</depend>
|
||||||
<depend>tf2_web_republisher</depend>
|
<depend>tf2_web_republisher</depend>
|
||||||
<depend>python-lxml</depend>
|
<depend condition="$ROS_PYTHON_VERSION == 2">python-lxml</depend>
|
||||||
|
<depend condition="$ROS_PYTHON_VERSION == 3">python3-lxml</depend>
|
||||||
<exec_depend>python-pymavlink</exec_depend>
|
<exec_depend>python-pymavlink</exec_depend>
|
||||||
<!-- Use test_depend for packages you need only for testing: -->
|
<!-- Use test_depend for packages you need only for testing: -->
|
||||||
<!-- <test_depend>gtest</test_depend> -->
|
<!-- <test_depend>gtest</test_depend> -->
|
||||||
|
|||||||
@@ -206,7 +206,7 @@ private:
|
|||||||
} catch (const tf2::TransformException& e) {
|
} catch (const tf2::TransformException& e) {
|
||||||
// Invalidate previous frame
|
// Invalidate previous frame
|
||||||
prev_.release();
|
prev_.release();
|
||||||
goto publish_debug;
|
return;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -218,10 +218,6 @@ private:
|
|||||||
flow_.quality = (uint8_t)(response * 255);
|
flow_.quality = (uint8_t)(response * 255);
|
||||||
flow_pub_.publish(flow_);
|
flow_pub_.publish(flow_);
|
||||||
|
|
||||||
prev_ = curr_.clone();
|
|
||||||
prev_stamp_ = msg->header.stamp;
|
|
||||||
|
|
||||||
publish_debug:
|
|
||||||
// Publish debug image
|
// Publish debug image
|
||||||
if (img_pub_.getNumSubscribers() > 0) {
|
if (img_pub_.getNumSubscribers() > 0) {
|
||||||
// publish debug image
|
// publish debug image
|
||||||
@@ -238,9 +234,12 @@ publish_debug:
|
|||||||
static geometry_msgs::TwistStamped velo;
|
static geometry_msgs::TwistStamped velo;
|
||||||
velo.header.stamp = msg->header.stamp;
|
velo.header.stamp = msg->header.stamp;
|
||||||
velo.header.frame_id = fcu_frame_id_;
|
velo.header.frame_id = fcu_frame_id_;
|
||||||
velo.twist.angular.x = flow_fcu.vector.x / integration_time.toSec();
|
velo.twist.angular.x = flow_.integrated_x / integration_time.toSec();
|
||||||
velo.twist.angular.y = flow_fcu.vector.y / integration_time.toSec();
|
velo.twist.angular.y = flow_.integrated_y / integration_time.toSec();
|
||||||
velo_pub_.publish(velo);
|
velo_pub_.publish(velo);
|
||||||
|
|
||||||
|
prev_ = curr_.clone();
|
||||||
|
prev_stamp_ = msg->header.stamp;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -138,7 +138,7 @@ def mavlink_exec(cmd, timeout=3.0):
|
|||||||
timeout=3,
|
timeout=3,
|
||||||
baudrate=0,
|
baudrate=0,
|
||||||
count=len(cmd),
|
count=len(cmd),
|
||||||
data=map(ord, cmd.ljust(70, '\0')))
|
data=[ord(c) for c in cmd.ljust(70, '\0')])
|
||||||
msg.pack(link)
|
msg.pack(link)
|
||||||
ros_msg = mavlink.convert_to_rosmsg(msg)
|
ros_msg = mavlink.convert_to_rosmsg(msg)
|
||||||
mavlink_pub.publish(ros_msg)
|
mavlink_pub.publish(ros_msg)
|
||||||
@@ -609,7 +609,7 @@ def check_rangefinder():
|
|||||||
|
|
||||||
@check('Boot duration')
|
@check('Boot duration')
|
||||||
def check_boot_duration():
|
def check_boot_duration():
|
||||||
output = subprocess.check_output('systemd-analyze')
|
output = subprocess.check_output('systemd-analyze').decode()
|
||||||
r = re.compile(r'([\d\.]+)s\s*$', flags=re.MULTILINE)
|
r = re.compile(r'([\d\.]+)s\s*$', flags=re.MULTILINE)
|
||||||
duration = float(r.search(output).groups()[0])
|
duration = float(r.search(output).groups()[0])
|
||||||
if duration > 15:
|
if duration > 15:
|
||||||
@@ -620,7 +620,7 @@ def check_boot_duration():
|
|||||||
def check_cpu_usage():
|
def check_cpu_usage():
|
||||||
WHITELIST = 'nodelet',
|
WHITELIST = 'nodelet',
|
||||||
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)
|
output = subprocess.check_output(CMD, shell=True).decode()
|
||||||
processes = output.split('\n')
|
processes = output.split('\n')
|
||||||
for process in processes:
|
for process in processes:
|
||||||
if not process:
|
if not process:
|
||||||
@@ -636,7 +636,7 @@ def check_cpu_usage():
|
|||||||
def check_clover_service():
|
def check_clover_service():
|
||||||
try:
|
try:
|
||||||
output = subprocess.check_output('systemctl show -p ActiveState --value clover.service'.split(),
|
output = subprocess.check_output('systemctl show -p ActiveState --value clover.service'.split(),
|
||||||
stderr=subprocess.STDOUT)
|
stderr=subprocess.STDOUT).decode()
|
||||||
except subprocess.CalledProcessError as e:
|
except subprocess.CalledProcessError as e:
|
||||||
failure('systemctl returned %s: %s', e.returncode, e.output)
|
failure('systemctl returned %s: %s', e.returncode, e.output)
|
||||||
return
|
return
|
||||||
@@ -751,7 +751,7 @@ def check_rpi_health():
|
|||||||
# <parameter>=<value>
|
# <parameter>=<value>
|
||||||
# In case of `get_throttled`, <value> is a hexadecimal number
|
# In case of `get_throttled`, <value> is a hexadecimal number
|
||||||
# with some of the FLAGs OR'ed together
|
# with some of the FLAGs OR'ed together
|
||||||
output = subprocess.check_output(['vcgencmd', 'get_throttled'])
|
output = subprocess.check_output(['vcgencmd', 'get_throttled']).decode()
|
||||||
except OSError:
|
except OSError:
|
||||||
failure('could not call vcgencmd binary; not a Raspberry Pi?')
|
failure('could not call vcgencmd binary; not a Raspberry Pi?')
|
||||||
return
|
return
|
||||||
|
|||||||
@@ -496,16 +496,10 @@ inline void checkManualControl()
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (check_kill_switch) {
|
if (check_kill_switch) {
|
||||||
// switch values: https://github.com/PX4/PX4-Autopilot/blob/c302514a0809b1765fafd13c014d705446ae1113/msg/manual_control_setpoint.msg#L3
|
|
||||||
const uint8_t SWITCH_POS_NONE = 0; // switch is not mapped
|
|
||||||
const uint8_t SWITCH_POS_ON = 1; // switch activated
|
|
||||||
const uint8_t SWITCH_POS_MIDDLE = 2; // middle position
|
|
||||||
const uint8_t SWITCH_POS_OFF = 3; // switch not activated
|
|
||||||
|
|
||||||
const int KILL_SWITCH_BIT = 12; // https://github.com/PX4/Firmware/blob/c302514a0809b1765fafd13c014d705446ae1113/src/modules/mavlink/mavlink_messages.cpp#L3975
|
const int KILL_SWITCH_BIT = 12; // https://github.com/PX4/Firmware/blob/c302514a0809b1765fafd13c014d705446ae1113/src/modules/mavlink/mavlink_messages.cpp#L3975
|
||||||
uint8_t kill_switch = (manual_control.buttons & (0b11 << KILL_SWITCH_BIT)) >> KILL_SWITCH_BIT;
|
bool kill_switch = manual_control.buttons & (1 << KILL_SWITCH_BIT);
|
||||||
|
|
||||||
if (kill_switch == SWITCH_POS_ON)
|
if (kill_switch)
|
||||||
throw std::runtime_error("Kill switch is on");
|
throw std::runtime_error("Kill switch is on");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,9 +0,0 @@
|
|||||||
#!/usr/bin/env bash
|
|
||||||
|
|
||||||
# $ ./waitfile <file> <command> <args...>
|
|
||||||
# wait until <file> appears and then invoke <command> with <args>
|
|
||||||
|
|
||||||
echo "wait for file $1"
|
|
||||||
while [ ! -e "$1" ]; do sleep 1; done;
|
|
||||||
echo "file $1 appeared"
|
|
||||||
"${@:2}"
|
|
||||||
@@ -26,5 +26,26 @@ def test_simple_offboard_services_available():
|
|||||||
rospy.wait_for_service('land', timeout=5)
|
rospy.wait_for_service('land', timeout=5)
|
||||||
|
|
||||||
def test_web_video_server(node):
|
def test_web_video_server(node):
|
||||||
import urllib2
|
try:
|
||||||
urllib2.urlopen("http://localhost:8080").read()
|
# Python 2
|
||||||
|
import urllib2 as urllib
|
||||||
|
except ModuleNotFoundError:
|
||||||
|
# Python 3
|
||||||
|
import urllib.request as urllib
|
||||||
|
urllib.urlopen("http://localhost:8080").read()
|
||||||
|
|
||||||
|
def test_shell(node):
|
||||||
|
execute = rospy.ServiceProxy('exec', srv.Execute)
|
||||||
|
execute.wait_for_service(5)
|
||||||
|
|
||||||
|
res = execute(cmd='echo foo')
|
||||||
|
assert res.code == 0
|
||||||
|
assert res.output == 'foo\n'
|
||||||
|
|
||||||
|
res = execute(cmd='foo')
|
||||||
|
assert res.code == 32512
|
||||||
|
assert res.output == ''
|
||||||
|
|
||||||
|
res = execute(cmd='ls foo')
|
||||||
|
assert res.code == 512
|
||||||
|
assert res.output == ''
|
||||||
|
|||||||
@@ -1 +0,0 @@
|
|||||||
/tmp/clover.err
|
|
||||||
@@ -1 +0,0 @@
|
|||||||
/etc/clover_version
|
|
||||||
@@ -1,35 +1,25 @@
|
|||||||
<style>
|
<h1>Clover Drone Kit Tools</h1>
|
||||||
body { font-family: sans-serif; }
|
|
||||||
main { max-width: 600px; margin: 50px auto; }
|
|
||||||
</style>
|
|
||||||
|
|
||||||
<title>Clover Drone Kit Tools</title>
|
<ul>
|
||||||
|
<li><a href="docs">View documentation</a> (snapshot of <a href="https://clover.coex.tech">clover.coex.tech</a>)</li>
|
||||||
|
<li><a href="" id="wvs">View image topics</a> (<code>web_video_server</code>)</li>
|
||||||
|
<li><a href="" id="butterfly">Open web terminal</a> (<code>Butterfly</code>)</li>
|
||||||
|
<li><a href="viz.html">View 3D visualization</a> (<code>ros3djs</code>)</li>
|
||||||
|
<li><a href="aruco_map.html">3D visualization for markers map</a> (<code>ros3djs</code>)</li>
|
||||||
|
<li><a href="../clover_blocks/">Blocks programming</a> (<code>Blockly</code>)</li>
|
||||||
|
</ul>
|
||||||
|
|
||||||
<main>
|
<div class="version"></div>
|
||||||
<h1>Clover Drone Kit Tools</h1>
|
|
||||||
|
|
||||||
<ul>
|
|
||||||
<li><a href="docs">View documentation</a> (snapshot of <a href="https://clover.coex.tech">clover.coex.tech</a>)</li>
|
|
||||||
<li><a href="" id="wvs">View image topics</a> (<code>web_video_server</code>)</li>
|
|
||||||
<li><a href="" id="butterfly">Open web terminal</a> (<code>Butterfly</code>)</li>
|
|
||||||
<li><a href="viz.html">View 3D visualization</a> (<code>ros3djs</code>)</li>
|
|
||||||
<li><a href="aruco_map.html">3D visualization for markers map</a> (<code>ros3djs</code>)</li>
|
|
||||||
<li><a href="../clover_blocks/">Blocks programming</a> (<code>Blockly</code>)</li>
|
|
||||||
<li><a href="clover.err">Clover console</a> (<code>/tmp/clover.err</code>)</li>
|
|
||||||
</ul>
|
|
||||||
|
|
||||||
<div class="version"></div>
|
|
||||||
</main>
|
|
||||||
|
|
||||||
|
<script src="js/roslib.js"></script>
|
||||||
<script type="text/javascript">
|
<script type="text/javascript">
|
||||||
document.querySelector("#wvs").href = location.protocol + '//' + location.hostname + ':8080';
|
document.querySelector("#wvs").href = location.protocol + '//' + location.hostname + ':8080';
|
||||||
document.querySelector("#butterfly").href = location.protocol + '//' + location.hostname + ':57575';
|
document.querySelector("#butterfly").href = location.protocol + '//' + location.hostname + ':57575';
|
||||||
|
|
||||||
// Determine image version
|
// Determine image version
|
||||||
fetch('clover_version').then(function(response) {
|
var ros = new ROSLIB.Ros({ url: 'ws://' + location.hostname + ':9090' });
|
||||||
if (response.status !== 200) return;
|
var exec = new ROSLIB.Service({ ros: ros, name : '/exec', serviceType : 'clover/Execute' });
|
||||||
response.text().then(function(text) {
|
exec.callService(new ROSLIB.ServiceRequest({ cmd: 'cat /etc/clover_version' }), function(result) {
|
||||||
document.querySelector('.version').innerHTML = 'Version: <code>' + text + '</code>';
|
document.querySelector('.version').innerHTML = 'Version: ' + result.output;
|
||||||
});
|
|
||||||
});
|
});
|
||||||
</script>
|
</script>
|
||||||
|
|||||||
@@ -1,8 +0,0 @@
|
|||||||
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
|
||||||
Changelog for package clover_blocks
|
|
||||||
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
|
||||||
|
|
||||||
0.21.1 (2020-11-17)
|
|
||||||
-------------------
|
|
||||||
* First release of clover_blocks package to ROS
|
|
||||||
* Contributors: Oleg Kalachev
|
|
||||||
@@ -1,7 +1,7 @@
|
|||||||
<?xml version="1.0"?>
|
<?xml version="1.0"?>
|
||||||
<package format="2">
|
<package format="2">
|
||||||
<name>clover_blocks</name>
|
<name>clover_blocks</name>
|
||||||
<version>0.21.1</version>
|
<version>0.0.0</version>
|
||||||
<description>Blockly programming support for Clover</description>
|
<description>Blockly programming support for Clover</description>
|
||||||
<maintainer email="okalachev@gmail.com">Oleg Kalachev</maintainer>
|
<maintainer email="okalachev@gmail.com">Oleg Kalachev</maintainer>
|
||||||
<license>MIT</license>
|
<license>MIT</license>
|
||||||
|
|||||||
@@ -29,7 +29,7 @@
|
|||||||
</value>
|
</value>
|
||||||
<value name="Z">
|
<value name="Z">
|
||||||
<shadow type="math_number" id="n0ULZn64%k.:,l(,D?TZ">
|
<shadow type="math_number" id="n0ULZn64%k.:,l(,D?TZ">
|
||||||
<field name="NUM">1</field>
|
<field name="NUM">0</field>
|
||||||
</shadow>
|
</shadow>
|
||||||
</value>
|
</value>
|
||||||
<value name="ID">
|
<value name="ID">
|
||||||
|
|||||||
@@ -1,91 +1,106 @@
|
|||||||
<xml xmlns="https://developers.google.com/blockly/xml">
|
<xml xmlns="https://developers.google.com/blockly/xml">
|
||||||
<block type="controls_whileUntil" id="U1it{GcGuSS:=[xiwZr1" x="113" y="113">
|
<variables>
|
||||||
<field name="MODE">WHILE</field>
|
<variable id="_{V-S5HPBUl]CcJkL1Jw">led_count</variable>
|
||||||
<value name="BOOL">
|
</variables>
|
||||||
<block type="logic_boolean" id="]7ZDRwde}/RqjQCX}aVW">
|
<block type="variables_set" id="{)^J~:UMX%D;RWvztWLN" x="113" y="87">
|
||||||
<field name="BOOL">TRUE</field>
|
<field name="VAR" id="_{V-S5HPBUl]CcJkL1Jw">led_count</field>
|
||||||
|
<value name="VALUE">
|
||||||
|
<block type="math_number" id="V_W$3,VFwZjcc|?|1o`l">
|
||||||
|
<field name="NUM">58</field>
|
||||||
</block>
|
</block>
|
||||||
</value>
|
</value>
|
||||||
<statement name="DO">
|
<next>
|
||||||
<block type="set_effect" id="WI0zqOz/z3].cR/6UWHn">
|
<block type="controls_whileUntil" id="U1it{GcGuSS:=[xiwZr1">
|
||||||
<field name="EFFECT">FILL</field>
|
<field name="MODE">WHILE</field>
|
||||||
<value name="COLOR">
|
<value name="BOOL">
|
||||||
<shadow type="colour_picker" id="B`6;Xv{s2TFp8Yd=ZpSD">
|
<block type="logic_boolean" id="]7ZDRwde}/RqjQCX}aVW">
|
||||||
<field name="COLOUR">#000000</field>
|
<field name="BOOL">TRUE</field>
|
||||||
</shadow>
|
</block>
|
||||||
</value>
|
</value>
|
||||||
<next>
|
<statement name="DO">
|
||||||
<block type="set_led" id="^Vcs}ki?#ctf7rAchix$">
|
<block type="set_effect" id="WI0zqOz/z3].cR/6UWHn">
|
||||||
<value name="INDEX">
|
<field name="EFFECT">FILL</field>
|
||||||
<shadow type="math_number" id="U;VWW$[*LOF7Gf,~?YR7">
|
<value name="COLOR">
|
||||||
<field name="NUM">0</field>
|
<shadow type="colour_picker" id="B`6;Xv{s2TFp8Yd=ZpSD">
|
||||||
|
<field name="COLOUR">#000000</field>
|
||||||
</shadow>
|
</shadow>
|
||||||
<block type="math_arithmetic" id="AI6PZBd`]_Z%_~4c-%dB">
|
</value>
|
||||||
<field name="OP">MULTIPLY</field>
|
<next>
|
||||||
<value name="A">
|
<block type="set_led" id="^Vcs}ki?#ctf7rAchix$">
|
||||||
<shadow type="math_number" id="|p}X]`SedK3).F/;}NlB">
|
<value name="INDEX">
|
||||||
<field name="NUM">1</field>
|
<shadow type="math_number" id="U;VWW$[*LOF7Gf,~?YR7">
|
||||||
|
<field name="NUM">0</field>
|
||||||
</shadow>
|
</shadow>
|
||||||
<block type="math_arithmetic" id="-haE#:,cg{-J=NZERA;F">
|
<block type="math_arithmetic" id="AI6PZBd`]_Z%_~4c-%dB">
|
||||||
<field name="OP">DIVIDE</field>
|
<field name="OP">MULTIPLY</field>
|
||||||
<value name="A">
|
<value name="A">
|
||||||
<shadow type="math_number" id="::st;ot}[r]csqceURu*">
|
<shadow type="math_number" id="|p}X]`SedK3).F/;}NlB">
|
||||||
<field name="NUM">1</field>
|
<field name="NUM">1</field>
|
||||||
</shadow>
|
</shadow>
|
||||||
<block type="math_arithmetic" id="a%+LN)F~=Igg+,p02[qo">
|
<block type="math_arithmetic" id="-haE#:,cg{-J=NZERA;F">
|
||||||
<field name="OP">ADD</field>
|
<field name="OP">DIVIDE</field>
|
||||||
<value name="A">
|
<value name="A">
|
||||||
<shadow type="math_number" id="*yIGN((y)/^z0:f5:VDw">
|
<shadow type="math_number" id="::st;ot}[r]csqceURu*">
|
||||||
<field name="NUM">1</field>
|
<field name="NUM">1</field>
|
||||||
</shadow>
|
</shadow>
|
||||||
<block type="get_yaw" id="mf%77q30bEqNfc/3`Mtb">
|
<block type="math_arithmetic" id="a%+LN)F~=Igg+,p02[qo">
|
||||||
<field name="FRAME_ID">MAP</field>
|
<field name="OP">ADD</field>
|
||||||
<value name="ID">
|
<value name="A">
|
||||||
<shadow type="math_number" id="xb32G.N#ip`|^Xv*MOmY">
|
<shadow type="math_number" id="*yIGN((y)/^z0:f5:VDw">
|
||||||
<field name="NUM">0</field>
|
<field name="NUM">1</field>
|
||||||
|
</shadow>
|
||||||
|
<block type="get_yaw" id="mf%77q30bEqNfc/3`Mtb">
|
||||||
|
<field name="FRAME_ID">MAP</field>
|
||||||
|
<value name="ID">
|
||||||
|
<shadow type="math_number" id="xb32G.N#ip`|^Xv*MOmY">
|
||||||
|
<field name="NUM">0</field>
|
||||||
|
</shadow>
|
||||||
|
</value>
|
||||||
|
</block>
|
||||||
|
</value>
|
||||||
|
<value name="B">
|
||||||
|
<shadow type="math_number" id="T/fTrm;j2Azgav;gI{ZW">
|
||||||
|
<field name="NUM">180</field>
|
||||||
</shadow>
|
</shadow>
|
||||||
</value>
|
</value>
|
||||||
</block>
|
</block>
|
||||||
</value>
|
</value>
|
||||||
<value name="B">
|
<value name="B">
|
||||||
<shadow type="math_number" id="T/fTrm;j2Azgav;gI{ZW">
|
<shadow type="math_number" id="Wo1/ZCeir,u6/.e1H+BB">
|
||||||
<field name="NUM">180</field>
|
<field name="NUM">360</field>
|
||||||
</shadow>
|
</shadow>
|
||||||
</value>
|
</value>
|
||||||
</block>
|
</block>
|
||||||
</value>
|
</value>
|
||||||
<value name="B">
|
<value name="B">
|
||||||
<shadow type="math_number" id="Wo1/ZCeir,u6/.e1H+BB">
|
<shadow type="math_number" id="jENTcXz0C5/=)Xpd!}LL">
|
||||||
<field name="NUM">360</field>
|
<field name="NUM">1</field>
|
||||||
</shadow>
|
</shadow>
|
||||||
|
<block type="variables_get" id="Ko,`n=i88FY~`YbQLA?[">
|
||||||
|
<field name="VAR" id="_{V-S5HPBUl]CcJkL1Jw">led_count</field>
|
||||||
|
</block>
|
||||||
</value>
|
</value>
|
||||||
</block>
|
</block>
|
||||||
</value>
|
</value>
|
||||||
<value name="B">
|
<value name="COLOR">
|
||||||
<shadow type="math_number" id="jENTcXz0C5/=)Xpd!}LL">
|
<shadow type="colour_picker" id="+vw3bff.5c[=_w,Xm^C(">
|
||||||
<field name="NUM">1</field>
|
<field name="COLOUR">#3366ff</field>
|
||||||
</shadow>
|
|
||||||
<block type="led_count" id="vM@X8s!xa]v}AaK6PWF5"></block>
|
|
||||||
</value>
|
|
||||||
</block>
|
|
||||||
</value>
|
|
||||||
<value name="COLOR">
|
|
||||||
<shadow type="colour_picker" id="+vw3bff.5c[=_w,Xm^C(">
|
|
||||||
<field name="COLOUR">#3366ff</field>
|
|
||||||
</shadow>
|
|
||||||
</value>
|
|
||||||
<next>
|
|
||||||
<block type="wait" id="DT%f$bn1*1El5zsgUW8Y">
|
|
||||||
<value name="TIME">
|
|
||||||
<shadow type="math_number" id="~Y0hNY[_^#v@aZkE-TH[">
|
|
||||||
<field name="NUM">0.1</field>
|
|
||||||
</shadow>
|
</shadow>
|
||||||
</value>
|
</value>
|
||||||
|
<next>
|
||||||
|
<block type="wait" id="DT%f$bn1*1El5zsgUW8Y">
|
||||||
|
<value name="TIME">
|
||||||
|
<shadow type="math_number" id="~Y0hNY[_^#v@aZkE-TH[">
|
||||||
|
<field name="NUM">0.1</field>
|
||||||
|
</shadow>
|
||||||
|
</value>
|
||||||
|
</block>
|
||||||
|
</next>
|
||||||
</block>
|
</block>
|
||||||
</next>
|
</next>
|
||||||
</block>
|
</block>
|
||||||
</next>
|
</statement>
|
||||||
</block>
|
</block>
|
||||||
</statement>
|
</next>
|
||||||
</block>
|
</block>
|
||||||
</xml>
|
</xml>
|
||||||
@@ -11,8 +11,7 @@
|
|||||||
from __future__ import print_function
|
from __future__ import print_function
|
||||||
|
|
||||||
import rospy
|
import rospy
|
||||||
import os, sys
|
import os
|
||||||
import traceback
|
|
||||||
import threading
|
import threading
|
||||||
import re
|
import re
|
||||||
import uuid
|
import uuid
|
||||||
@@ -112,17 +111,12 @@ def run(req):
|
|||||||
'print': _print,
|
'print': _print,
|
||||||
'raw_input': _input}
|
'raw_input': _input}
|
||||||
try:
|
try:
|
||||||
exec req.code in g
|
exec(req.code, g)
|
||||||
except Stop:
|
except Stop:
|
||||||
rospy.loginfo('Program forced to stop')
|
rospy.loginfo('Program forced to stop')
|
||||||
except Exception as e:
|
except Exception as e:
|
||||||
rospy.logerr(str(e))
|
rospy.logerr(str(e))
|
||||||
traceback.print_exc()
|
error_pub.publish(str(e))
|
||||||
etype, value, tb = sys.exc_info()
|
|
||||||
fmt = traceback.format_exception(etype, value, tb)
|
|
||||||
fmt.pop(1) # remove 'clover_blocks' file frame
|
|
||||||
exc_info = ''.join(fmt)
|
|
||||||
error_pub.publish(str(e) + '\n\n' + exc_info)
|
|
||||||
|
|
||||||
rospy.loginfo('Program terminated')
|
rospy.loginfo('Program terminated')
|
||||||
running_lock.release()
|
running_lock.release()
|
||||||
|
|||||||
@@ -353,17 +353,6 @@ Blockly.Blocks['set_effect'] = {
|
|||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
Blockly.Blocks['led_count'] = {
|
|
||||||
init: function () {
|
|
||||||
this.appendDummyInput()
|
|
||||||
.appendField("LED count");
|
|
||||||
this.setOutput(true, "Number");
|
|
||||||
this.setColour(COLOR_LED);
|
|
||||||
this.setTooltip("Returns the number of LEDs (configured in led.launch).");
|
|
||||||
this.setHelpUrl(DOCS_URL + '#' + this.type);
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
Blockly.Blocks['take_off'] = {
|
Blockly.Blocks['take_off'] = {
|
||||||
init: function () {
|
init: function () {
|
||||||
this.appendValueInput("ALT")
|
this.appendValueInput("ALT")
|
||||||
@@ -546,7 +535,7 @@ Blockly.Blocks['gpio_read'] = {
|
|||||||
this.setOutput(true, "Boolean");
|
this.setOutput(true, "Boolean");
|
||||||
this.setColour(COLOR_GPIO);
|
this.setColour(COLOR_GPIO);
|
||||||
this.setTooltip("Returns if there is voltage on a GPIO pin.");
|
this.setTooltip("Returns if there is voltage on a GPIO pin.");
|
||||||
this.setHelpUrl(DOCS_URL + '#GPIO');
|
this.setHelpUrl(DOCS_URL + '#' + this.type);
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
@@ -563,7 +552,7 @@ Blockly.Blocks['gpio_write'] = {
|
|||||||
this.setPreviousStatement(true, null);
|
this.setPreviousStatement(true, null);
|
||||||
this.setNextStatement(true, null);
|
this.setNextStatement(true, null);
|
||||||
this.setTooltip("Set GPIO pin level.");
|
this.setTooltip("Set GPIO pin level.");
|
||||||
this.setHelpUrl(DOCS_URL + '#GPIO');
|
this.setHelpUrl(DOCS_URL + '#' + this.type);
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
@@ -579,24 +568,7 @@ Blockly.Blocks['set_servo'] = {
|
|||||||
this.setColour(COLOR_GPIO);
|
this.setColour(COLOR_GPIO);
|
||||||
this.setPreviousStatement(true, null);
|
this.setPreviousStatement(true, null);
|
||||||
this.setNextStatement(true, null);
|
this.setNextStatement(true, null);
|
||||||
this.setTooltip("Set PWM on a GPIO pin to control servo. PWM is specified in range of 500–2500 μs.");
|
this.setTooltip("Set PWM on a GPIO pin to control servo. PWM is specified in range of 500–2500 ms.");
|
||||||
this.setHelpUrl(DOCS_URL + '#GPIO');
|
this.setHelpUrl(DOCS_URL + '#' + this.type);
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
Blockly.Blocks['set_duty_cycle'] = {
|
|
||||||
init: function () {
|
|
||||||
this.appendValueInput("PIN")
|
|
||||||
.setCheck("Number")
|
|
||||||
.appendField("set GPIO pin");
|
|
||||||
this.appendValueInput("DUTY_CYCLE")
|
|
||||||
.setCheck("Number")
|
|
||||||
.appendField("to duty cycle");
|
|
||||||
this.setInputsInline(true);
|
|
||||||
this.setColour(COLOR_GPIO);
|
|
||||||
this.setPreviousStatement(true, null);
|
|
||||||
this.setNextStatement(true, null);
|
|
||||||
this.setTooltip("Set PWM duty cycle on a GPIO pin (better to control LEDs, etc). Duty cycle is set in range of 0–1.");
|
|
||||||
this.setHelpUrl(DOCS_URL + '#GPIO');
|
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -106,7 +106,6 @@
|
|||||||
<value name="INDEX"><shadow type="math_number"><field name="NUM">0</field></shadow></value>
|
<value name="INDEX"><shadow type="math_number"><field name="NUM">0</field></shadow></value>
|
||||||
<value name="COLOR"><shadow type="colour_picker"></shadow></value>
|
<value name="COLOR"><shadow type="colour_picker"></shadow></value>
|
||||||
</block>
|
</block>
|
||||||
<block type="led_count"></block>
|
|
||||||
</category>
|
</category>
|
||||||
<category name="GPIO" colour="#5b97cc">
|
<category name="GPIO" colour="#5b97cc">
|
||||||
<block type="gpio_read">
|
<block type="gpio_read">
|
||||||
@@ -120,10 +119,6 @@
|
|||||||
<value name="PIN"><shadow type="math_number"><field name="NUM">1</field></shadow></value>
|
<value name="PIN"><shadow type="math_number"><field name="NUM">1</field></shadow></value>
|
||||||
<value name="PWM"><shadow type="math_number"><field name="NUM">1500</field></shadow></value>
|
<value name="PWM"><shadow type="math_number"><field name="NUM">1500</field></shadow></value>
|
||||||
</block>
|
</block>
|
||||||
<block type="set_duty_cycle">
|
|
||||||
<value name="PIN"><shadow type="math_number"><field name="NUM">1</field></shadow></value>
|
|
||||||
<value name="DUTY_CYCLE"><shadow type="math_number"><field name="NUM">0.5</field></shadow></value>
|
|
||||||
</block>
|
|
||||||
</category>
|
</category>
|
||||||
<sep></sep>
|
<sep></sep>
|
||||||
<category name="Logic" colour="#5b80a5">
|
<category name="Logic" colour="#5b80a5">
|
||||||
|
|||||||
@@ -15,7 +15,7 @@ Blockly.Python.addReservedWords('_b,_print');
|
|||||||
Blockly.Python.addReservedWords('rospy,srv,Trigger,get_telemetry,navigate,set_velocity,land');
|
Blockly.Python.addReservedWords('rospy,srv,Trigger,get_telemetry,navigate,set_velocity,land');
|
||||||
Blockly.Python.addReservedWords('navigate_wait,land_wait,wait_arrival,wait_yaw,get_distance');
|
Blockly.Python.addReservedWords('navigate_wait,land_wait,wait_arrival,wait_yaw,get_distance');
|
||||||
Blockly.Python.addReservedWords('pigpio,pi,Range');
|
Blockly.Python.addReservedWords('pigpio,pi,Range');
|
||||||
Blockly.Python.addReservedWords('SetLEDEffect,set_effect,led_count,get_led_count');
|
Blockly.Python.addReservedWords('SetLEDEffect,set_effect');
|
||||||
Blockly.Python.addReservedWords('SetLEDs,LEDState,set_leds');
|
Blockly.Python.addReservedWords('SetLEDs,LEDState,set_leds');
|
||||||
|
|
||||||
const IMPORT_SRV = `from clover import srv
|
const IMPORT_SRV = `from clover import srv
|
||||||
@@ -87,9 +87,6 @@ function generateROSDefinitions() {
|
|||||||
Blockly.Python.definitions_['import_set_led'] = 'from led_msgs.srv import SetLEDs\nfrom led_msgs.msg import LEDState';
|
Blockly.Python.definitions_['import_set_led'] = 'from led_msgs.srv import SetLEDs\nfrom led_msgs.msg import LEDState';
|
||||||
code += `set_leds = rospy.ServiceProxy('led/set_leds', SetLEDs, persistent=True)\n`;
|
code += `set_leds = rospy.ServiceProxy('led/set_leds', SetLEDs, persistent=True)\n`;
|
||||||
}
|
}
|
||||||
if (rosDefinitions.ledStateArray) {
|
|
||||||
Blockly.Python.definitions_['import_led_state_array'] = 'from led_msgs.msg import LEDStateArray';
|
|
||||||
}
|
|
||||||
if (rosDefinitions.navigateWait) {
|
if (rosDefinitions.navigateWait) {
|
||||||
Blockly.Python.definitions_['import_math'] = 'import math';
|
Blockly.Python.definitions_['import_math'] = 'import math';
|
||||||
code += NAVIGATE_WAIT();
|
code += NAVIGATE_WAIT();
|
||||||
@@ -394,45 +391,26 @@ Blockly.Python.set_led = function(block) {
|
|||||||
return `set_leds([LEDState(index=${index}, r=${color.r}, g=${color.g}, b=${color.b})])\n`;
|
return `set_leds([LEDState(index=${index}, r=${color.r}, g=${color.g}, b=${color.b})])\n`;
|
||||||
} else {
|
} else {
|
||||||
let parseColor = Blockly.Python.provideFunction_('parse_color', [PARSE_COLOR]);
|
let parseColor = Blockly.Python.provideFunction_('parse_color', [PARSE_COLOR]);
|
||||||
return `set_leds([LEDState(index=${index}, **${parseColor}(${colorCode}))])\n`;
|
return `set_leds([LEDState(index=${index}, **${parseColor}(${colorCode})])\n`;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
const GET_LED_COUNT = `led_count = None
|
|
||||||
|
|
||||||
def get_led_count():
|
|
||||||
global led_count
|
|
||||||
if led_count is None:
|
|
||||||
led_count = len(rospy.wait_for_message('led/state', LEDStateArray, timeout=10).leds)
|
|
||||||
return led_count\n`;
|
|
||||||
|
|
||||||
Blockly.Python.led_count = function(block) {
|
|
||||||
rosDefinitions.ledStateArray = true;
|
|
||||||
initNode();
|
|
||||||
Blockly.Python.definitions_['get_led_count'] = GET_LED_COUNT;
|
|
||||||
return [`get_led_count()`, Blockly.Python.ORDER_FUNCTION_CALL]
|
|
||||||
}
|
|
||||||
|
|
||||||
function pigpio() {
|
function pigpio() {
|
||||||
Blockly.Python.definitions_['import_pigpio'] = 'import pigpio';
|
Blockly.Python.definitions_['import_pigpio'] = 'import pigpio';
|
||||||
Blockly.Python.definitions_['init_pigpio'] = 'pi = pigpio.pi()';
|
Blockly.Python.definitions_['init_pigpio'] = 'pi = pigpio.pi()';
|
||||||
}
|
}
|
||||||
|
|
||||||
const GPIO_READ = `\ndef gpio_read(pin):
|
const GPIO_READ = `\ndef gpio_read(pin):
|
||||||
pi.set_mode(pin, pigpio.INPUT)
|
pi.set_mode(pin, pigpio.INPUT)
|
||||||
return pi.read(pin)\n`;
|
return pi.read(pin)\n`;
|
||||||
|
|
||||||
const GPIO_WRITE = `\ndef gpio_write(pin, level):
|
const GPIO_WRITE = `\ndef gpio_write(pin, level):
|
||||||
pi.set_mode(pin, pigpio.OUTPUT)
|
pi.set_mode(pin, pigpio.OUTPUT)
|
||||||
pi.write(pin, level)\n`;
|
pi.write(pin, level)\n`;
|
||||||
|
|
||||||
const SET_SERVO = `\ndef set_servo(pin, pwm):
|
const SET_SERVO = `\ndef set_servo(pin, pwm):
|
||||||
pi.set_mode(pin, pigpio.OUTPUT)
|
pi.set_mode(pin, pigpio.OUTPUT)
|
||||||
pi.set_servo_pulsewidth(pin, pwm)\n`;
|
pi.set_servo_pulsewidth(pin, pwm)\n`;
|
||||||
|
|
||||||
const SET_DUTY_CYCLE = `\ndef set_duty_cycle(pin, duty_cycle):
|
|
||||||
pi.set_mode(pin, pigpio.OUTPUT)
|
|
||||||
pi.set_PWM_dutycycle(pin, duty_cycle * 255)\n`;
|
|
||||||
|
|
||||||
Blockly.Python.gpio_read = function(block) {
|
Blockly.Python.gpio_read = function(block) {
|
||||||
pigpio();
|
pigpio();
|
||||||
@@ -456,11 +434,3 @@ Blockly.Python.set_servo = function(block) {
|
|||||||
var pwm = Blockly.Python.valueToCode(block, 'PWM', Blockly.Python.ORDER_NONE);
|
var pwm = Blockly.Python.valueToCode(block, 'PWM', Blockly.Python.ORDER_NONE);
|
||||||
return `set_servo(${pin}, ${pwm})\n`;
|
return `set_servo(${pin}, ${pwm})\n`;
|
||||||
}
|
}
|
||||||
|
|
||||||
Blockly.Python.set_duty_cycle = function(block) {
|
|
||||||
pigpio();
|
|
||||||
Blockly.Python.definitions_['set_duty_cycle'] = SET_DUTY_CYCLE;
|
|
||||||
var pin = Blockly.Python.valueToCode(block, 'PIN', Blockly.Python.ORDER_NONE);
|
|
||||||
var dutyCycle = Blockly.Python.valueToCode(block, 'DUTY_CYCLE', Blockly.Python.ORDER_NONE);
|
|
||||||
return `set_duty_cycle(${pin}, ${dutyCycle})\n`;
|
|
||||||
}
|
|
||||||
|
|||||||
@@ -1,9 +0,0 @@
|
|||||||
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
|
||||||
Changelog for package clover_description
|
|
||||||
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
|
||||||
|
|
||||||
0.21.1 (2020-11-17)
|
|
||||||
-------------------
|
|
||||||
* First release of clover_description package to ROS
|
|
||||||
* Contributors: Alexey Rogachevskiy
|
|
||||||
|
|
||||||
@@ -1,6 +1,6 @@
|
|||||||
<package format="2">
|
<package format="2">
|
||||||
<name>clover_description</name>
|
<name>clover_description</name>
|
||||||
<version>0.21.1</version>
|
<version>0.0.1</version>
|
||||||
<description>The clover_description package provides URDF models of the Clover series of quadcopters.</description>
|
<description>The clover_description package provides URDF models of the Clover series of quadcopters.</description>
|
||||||
|
|
||||||
<maintainer email="sfalexrog@gmail.com">Alexey Rogachevskiy</maintainer>
|
<maintainer email="sfalexrog@gmail.com">Alexey Rogachevskiy</maintainer>
|
||||||
|
|||||||
@@ -1,8 +0,0 @@
|
|||||||
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
|
||||||
Changelog for package clover_simulation
|
|
||||||
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
|
||||||
|
|
||||||
0.21.1 (2020-11-17)
|
|
||||||
-------------------
|
|
||||||
* First release of clover_simulation package to ROS
|
|
||||||
* Contributors: Alexey Rogachevskiy
|
|
||||||
@@ -52,7 +52,7 @@ target_compile_options(throttling_camera PRIVATE -std=c++11)
|
|||||||
add_dependencies(throttling_camera ${${PROJECT_NAME}_EXPORTED_TARGETS} ${catkin_EXPORTED_TARGETS})
|
add_dependencies(throttling_camera ${${PROJECT_NAME}_EXPORTED_TARGETS} ${catkin_EXPORTED_TARGETS})
|
||||||
|
|
||||||
install(DIRECTORY launch DESTINATION ${CATKIN_PACKAGE_SHARE_DESTINATION})
|
install(DIRECTORY launch DESTINATION ${CATKIN_PACKAGE_SHARE_DESTINATION})
|
||||||
install(DIRECTORY models DESTINATION ${CATKIN_PACKAGE_SHARE_DESTINATION})
|
install(DIRECTORY meshes DESTINATION ${CATKIN_PACKAGE_SHARE_DESTINATION})
|
||||||
install(DIRECTORY resources DESTINATION ${CATKIN_PACKAGE_SHARE_DESTINATION})
|
install(DIRECTORY resources DESTINATION ${CATKIN_PACKAGE_SHARE_DESTINATION})
|
||||||
|
|
||||||
catkin_install_python(PROGRAMS scripts/aruco_gen
|
catkin_install_python(PROGRAMS scripts/aruco_gen
|
||||||
|
|||||||
@@ -1,5 +1,4 @@
|
|||||||
<launch>
|
<launch>
|
||||||
<arg name="type" default="gazebo"/> <!-- gazebo, jmavsim, none (only clover packages) -->
|
|
||||||
<arg name="mav_id" default="0"/>
|
<arg name="mav_id" default="0"/>
|
||||||
<arg name="est" default="ekf2"/> <!-- PX4 estimator: lpe, ekf2 -->
|
<arg name="est" default="ekf2"/> <!-- PX4 estimator: lpe, ekf2 -->
|
||||||
<arg name="vehicle" default="clover"/> <!-- PX4 vehicle configuration: clover, clover_vpe -->
|
<arg name="vehicle" default="clover"/> <!-- PX4 vehicle configuration: clover, clover_vpe -->
|
||||||
@@ -10,22 +9,22 @@
|
|||||||
<arg name="use_clover_physics" default="false"/> <!-- Use inertial parameters from CAD models -->
|
<arg name="use_clover_physics" default="false"/> <!-- Use inertial parameters from CAD models -->
|
||||||
|
|
||||||
<!-- Gazebo instance -->
|
<!-- Gazebo instance -->
|
||||||
<include file="$(find gazebo_ros)/launch/empty_world.launch" if="$(eval type == 'gazebo')">
|
<include file="$(find gazebo_ros)/launch/empty_world.launch">
|
||||||
<!-- Workaround for crashes in VMware -->
|
<!-- Workaround for crashes in VMware -->
|
||||||
<env name="SVGA_VGPU10" value="0"/>
|
<env name="SVGA_VGPU10" value="0"/>
|
||||||
<arg name="gui" value="true"/>
|
<arg name="gui" value="true"/>
|
||||||
<arg name="world_name" value="$(find clover_simulation)/resources/worlds/clover_aruco.world"/>
|
<arg name="world_name" value="$(find clover_simulation)/resources/worlds/clover.world"/>
|
||||||
<arg name="verbose" value="true"/>
|
<arg name="verbose" value="true"/>
|
||||||
</include>
|
</include>
|
||||||
|
|
||||||
<!-- PX4 instance -->
|
<!-- PX4 instance -->
|
||||||
<node name="sitl_$(arg mav_id)" pkg="px4" type="px4" output="screen" args="$(find px4)/ROMFS/px4fmu_common -s etc/init.d-posix/rcS -i $(arg mav_id)" unless="$(eval type == 'none')">
|
<node name="sitl_$(arg mav_id)" pkg="px4" type="px4" output="screen" args="$(find px4)/ROMFS/px4fmu_common -s etc/init.d-posix/rcS -i $(arg mav_id)">
|
||||||
<env name="PX4_SIM_MODEL" value="$(arg vehicle)"/>
|
<env name="PX4_SIM_MODEL" value="$(arg vehicle)"/>
|
||||||
<env name="PX4_ESTIMATOR" value="$(arg est)"/>
|
<env name="PX4_ESTIMATOR" value="$(arg est)"/>
|
||||||
</node>
|
</node>
|
||||||
|
|
||||||
<!-- Clover model -->
|
<!-- Clover model -->
|
||||||
<include file="$(find clover_description)/launch/spawn_drone.launch" if="$(eval type == 'gazebo')">
|
<include file="$(find clover_description)/launch/spawn_drone.launch">
|
||||||
<arg name="main_camera" value="$(arg main_camera)"/>
|
<arg name="main_camera" value="$(arg main_camera)"/>
|
||||||
<arg name="rangefinder" value="$(arg rangefinder)"/>
|
<arg name="rangefinder" value="$(arg rangefinder)"/>
|
||||||
<arg name="led" value="$(arg led)"/>
|
<arg name="led" value="$(arg led)"/>
|
||||||
@@ -33,20 +32,10 @@
|
|||||||
<arg name="use_clover_physics" value="$(arg use_clover_physics)"/>
|
<arg name="use_clover_physics" value="$(arg use_clover_physics)"/>
|
||||||
</include>
|
</include>
|
||||||
|
|
||||||
<node name="jmavsim" pkg="px4" type="jmavsim_run.sh" output="screen" if="$(eval type == 'jmavsim')"/>
|
|
||||||
|
|
||||||
<param name="use_sim_time" value="false" if="$(eval type == 'jmavsim')"/>
|
|
||||||
|
|
||||||
<!-- Clover services -->
|
<!-- Clover services -->
|
||||||
<include file="$(find clover)/launch/clover.launch">
|
<include file="$(find clover)/launch/clover.launch">
|
||||||
<arg name="simulator" value="true"/>
|
<arg name="simulator" value="true"/>
|
||||||
<arg name="fcu_conn" value="sitl"/>
|
<arg name="fcu_conn" value="sitl"/>
|
||||||
<arg name="fcu_ip" value="127.0.0.1"/>
|
<arg name="fcu_ip" value="127.0.0.1"/>
|
||||||
<arg name="gcs_bridge" value=""/>
|
|
||||||
<arg name="rc" default="false"/>
|
|
||||||
<arg name="web_video_server" default="false" if="$(eval type == 'jmavsim')"/>
|
|
||||||
<arg name="main_camera" default="false" if="$(eval type == 'jmavsim')"/>
|
|
||||||
<arg name="aruco" default="false" if="$(eval type == 'jmavsim')"/>
|
|
||||||
<arg name="led" default="false" if="$(eval type == 'jmavsim')"/>
|
|
||||||
</include>
|
</include>
|
||||||
</launch>
|
</launch>
|
||||||
|
|||||||
|
Before Width: | Height: | Size: 94 B |
|
Before Width: | Height: | Size: 93 B |
|
Before Width: | Height: | Size: 94 B |
|
Before Width: | Height: | Size: 94 B |
|
Before Width: | Height: | Size: 93 B |
|
Before Width: | Height: | Size: 93 B |
|
Before Width: | Height: | Size: 94 B |
|
Before Width: | Height: | Size: 94 B |
|
Before Width: | Height: | Size: 94 B |
|
Before Width: | Height: | Size: 94 B |
|
Before Width: | Height: | Size: 94 B |
|
Before Width: | Height: | Size: 94 B |
|
Before Width: | Height: | Size: 94 B |
|
Before Width: | Height: | Size: 93 B |
|
Before Width: | Height: | Size: 94 B |
|
Before Width: | Height: | Size: 94 B |
|
Before Width: | Height: | Size: 94 B |
|
Before Width: | Height: | Size: 94 B |
|
Before Width: | Height: | Size: 94 B |
|
Before Width: | Height: | Size: 93 B |
|
Before Width: | Height: | Size: 94 B |
|
Before Width: | Height: | Size: 94 B |
|
Before Width: | Height: | Size: 94 B |
|
Before Width: | Height: | Size: 94 B |
|
Before Width: | Height: | Size: 94 B |
|
Before Width: | Height: | Size: 94 B |
|
Before Width: | Height: | Size: 93 B |
|
Before Width: | Height: | Size: 93 B |
|
Before Width: | Height: | Size: 93 B |
|
Before Width: | Height: | Size: 94 B |
|
Before Width: | Height: | Size: 93 B |
|
Before Width: | Height: | Size: 93 B |
|
Before Width: | Height: | Size: 94 B |
|
Before Width: | Height: | Size: 94 B |
|
Before Width: | Height: | Size: 94 B |
|
Before Width: | Height: | Size: 94 B |
|
Before Width: | Height: | Size: 94 B |
|
Before Width: | Height: | Size: 94 B |
|
Before Width: | Height: | Size: 94 B |
|
Before Width: | Height: | Size: 94 B |
|
Before Width: | Height: | Size: 94 B |