Compare commits
257 Commits
v0.20-rc.3
...
v0.21.2-qb
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
720b7d4274 | ||
|
|
efaddd34c8 | ||
|
|
5d29453ae0 | ||
|
|
b1f104ce5e | ||
|
|
80177b3ea4 | ||
|
|
3223d3817e | ||
|
|
4612f7e9f0 | ||
|
|
a026410fdb | ||
|
|
dd1a212cd0 | ||
|
|
20b6824012 | ||
|
|
6f6933234c | ||
|
|
3edafbef97 | ||
|
|
7740a136ce | ||
|
|
380112de6a | ||
|
|
79f5c6d0e7 | ||
|
|
e207b55966 | ||
|
|
043a4ad67c | ||
|
|
dbeb2b354d | ||
|
|
6134965f2a | ||
|
|
976bb7aeea | ||
|
|
faa0e6d8d2 | ||
|
|
d02151aedd | ||
|
|
7f0606397e | ||
|
|
fb2842a0a1 | ||
|
|
9a9621ab4b | ||
|
|
171804149c | ||
|
|
0cb7494023 | ||
|
|
e0a81e0ca8 | ||
|
|
1e5e9cdc43 | ||
|
|
5e315c477e | ||
|
|
f45000f595 | ||
|
|
48a1385a1a | ||
|
|
765c470baa | ||
|
|
fd69beed7b | ||
|
|
1d4179bccf | ||
|
|
0b2095bbb8 | ||
|
|
a0436fbcc5 | ||
|
|
aee867d6bc | ||
|
|
3c078ab92f | ||
|
|
d780aedb88 | ||
|
|
a16d9d80fc | ||
|
|
10d250d96a | ||
|
|
acdcf20392 | ||
|
|
796d614f5e | ||
|
|
f8de7443d7 | ||
|
|
5c3ffdbeb6 | ||
|
|
1c732137c6 | ||
|
|
345aad9e64 | ||
|
|
02c67ea71a | ||
|
|
050e0fedb9 | ||
|
|
0e9b54934c | ||
|
|
793b614b7b | ||
|
|
62ab5c2357 | ||
|
|
181a78e4a9 | ||
|
|
c72eb0c027 | ||
|
|
5d99e44c30 | ||
|
|
5eb9b4acbe | ||
|
|
30ada8f311 | ||
|
|
e717829945 | ||
|
|
50dc17badb | ||
|
|
1dea541df2 | ||
|
|
d6b950b726 | ||
|
|
e2a1d3aaeb | ||
|
|
165e4d1a61 | ||
|
|
4f631300d4 | ||
|
|
e252a1cddc | ||
|
|
25dd17c286 | ||
|
|
b9395e3d18 | ||
|
|
a32dd7dcdd | ||
|
|
1e12e34070 | ||
|
|
3ff675d794 | ||
|
|
bb3e4befe5 | ||
|
|
fe71007ebd | ||
|
|
68cec159f7 | ||
|
|
4e8127f690 | ||
|
|
8f78f2b6e4 | ||
|
|
c8163cd38b | ||
|
|
7831992d6a | ||
|
|
873befdba9 | ||
|
|
c3cbc305c3 | ||
|
|
b71e802a2e | ||
|
|
3c5f2c958e | ||
|
|
267993aec4 | ||
|
|
86dd42c3b3 | ||
|
|
9d338d843b | ||
|
|
3e100bee91 | ||
|
|
8a29b9a37a | ||
|
|
2e80a06db1 | ||
|
|
0003985c3b | ||
|
|
f250916ede | ||
|
|
ee2944a1d3 | ||
|
|
a088524468 | ||
|
|
215fe237ca | ||
|
|
8c1b5c19d0 | ||
|
|
779dfb3f4f | ||
|
|
23d503adc5 | ||
|
|
0350ecbff7 | ||
|
|
12bed337dc | ||
|
|
6a1b609ccd | ||
|
|
3d5c51a42e | ||
|
|
3702ed0c86 | ||
|
|
741abadb54 | ||
|
|
c6dc732867 | ||
|
|
ba76e51966 | ||
|
|
7951f0e2ba | ||
|
|
cd58c03c0f | ||
|
|
ce6b2530c4 | ||
|
|
14e4af76aa | ||
|
|
f3f1557b0b | ||
|
|
18d410db24 | ||
|
|
207dc88579 | ||
|
|
58f6ac4b39 | ||
|
|
688e4f0ca9 | ||
|
|
7cbe823700 | ||
|
|
df681e0a79 | ||
|
|
8aad2fc363 | ||
|
|
3c8dd14c9d | ||
|
|
3a20bc3212 | ||
|
|
1105cd8750 | ||
|
|
43d7e7c70b | ||
|
|
7a1e885df1 | ||
|
|
9a9c2d5c9f | ||
|
|
eaeb146878 | ||
|
|
2452be05ff | ||
|
|
a4336a39c9 | ||
|
|
9cdf7dea41 | ||
|
|
b90dc3c020 | ||
|
|
91252d8d50 | ||
|
|
c4b94390e9 | ||
|
|
1b4167365e | ||
|
|
01ec592abb | ||
|
|
e2e2e04381 | ||
|
|
27e0189cf5 | ||
|
|
e3d89cbc4c | ||
|
|
a0ac85e0d3 | ||
|
|
83e5911110 | ||
|
|
05d634d2d3 | ||
|
|
4967d651bd | ||
|
|
91f948d3f4 | ||
|
|
ebf55244f4 | ||
|
|
5b6d08e25d | ||
|
|
8036214406 | ||
|
|
5d3c8c89cb | ||
|
|
2075fa52ef | ||
|
|
b0e1e1ffae | ||
|
|
4482f973db | ||
|
|
b1c7ee6b66 | ||
|
|
ff9e669352 | ||
|
|
6c8291749f | ||
|
|
039d2438cd | ||
|
|
048a605f2f | ||
|
|
0e0d4fe5cc | ||
|
|
37bbd7522c | ||
|
|
f206b2ea18 | ||
|
|
ae7f3ccfbc | ||
|
|
da28c61f1e | ||
|
|
b7ce588b07 | ||
|
|
f663a62c1e | ||
|
|
5b370ee96b | ||
|
|
e0512c209e | ||
|
|
7385f673de | ||
|
|
5629b0a9b3 | ||
|
|
9de0034fb9 | ||
|
|
ae29fe00d3 | ||
|
|
7295c6c040 | ||
|
|
11bdf2d3da | ||
|
|
89ccca3c30 | ||
|
|
50218a8822 | ||
|
|
11d5da5db2 | ||
|
|
757129782e | ||
|
|
f7c1f4330d | ||
|
|
b36292cdb8 | ||
|
|
a9f6fe329b | ||
|
|
f89cc92736 | ||
|
|
60755fa1b5 | ||
|
|
792352d072 | ||
|
|
2f6d9639c1 | ||
|
|
d52175bb30 | ||
|
|
be6e894b80 | ||
|
|
2f6125ce54 | ||
|
|
c6a238c671 | ||
|
|
28851f39ad | ||
|
|
4a2fbf3e22 | ||
|
|
c3b549df0d | ||
|
|
21d922beb2 | ||
|
|
88ef00e043 | ||
|
|
1b85a9cdf2 | ||
|
|
d5a79babad | ||
|
|
4d80e6f6cf | ||
|
|
8ce4de191b | ||
|
|
ecaab1650f | ||
|
|
a62107132d | ||
|
|
423490304b | ||
|
|
ee9c956fc7 | ||
|
|
14e49a4f7b | ||
|
|
d4d25c61a2 | ||
|
|
106209d79b | ||
|
|
333cf9655f | ||
|
|
2ddf831842 | ||
|
|
68f23babcc | ||
|
|
4f0a099152 | ||
|
|
acfb858598 | ||
|
|
c0f15fc1e6 | ||
|
|
e94e552da3 | ||
|
|
6b5e3464f1 | ||
|
|
768c0be5a5 | ||
|
|
892c6f853b | ||
|
|
8b690900b9 | ||
|
|
17c210919d | ||
|
|
ebeb3f58d6 | ||
|
|
3b19346a44 | ||
|
|
32d27f3f66 | ||
|
|
585af026d4 | ||
|
|
b52f702723 | ||
|
|
3e4f1ab8a9 | ||
|
|
513f4f419a | ||
|
|
6db5602a5a | ||
|
|
fb17a3f926 | ||
|
|
70e1675f9a | ||
|
|
e03eaa51c4 | ||
|
|
b346af92ae | ||
|
|
cb2cf48f39 | ||
|
|
ebec850010 | ||
|
|
5a8db188f6 | ||
|
|
4376bbb723 | ||
|
|
1d694e1a15 | ||
|
|
54de7fca3a | ||
|
|
32f5584082 | ||
|
|
d7c0fb33ff | ||
|
|
d16e7bf155 | ||
|
|
26bd1e2d8f | ||
|
|
e12577cf0e | ||
|
|
12544a69af | ||
|
|
f471280bef | ||
|
|
2ff9887ac4 | ||
|
|
2ecfb28a5d | ||
|
|
091483226f | ||
|
|
af16414c77 | ||
|
|
696214e717 | ||
|
|
15fd156ce0 | ||
|
|
82bfb961a4 | ||
|
|
c50637c60f | ||
|
|
a26f0f41e7 | ||
|
|
28690491c2 | ||
|
|
ca1323faf3 | ||
|
|
b713b49f3f | ||
|
|
62a77519e6 | ||
|
|
e1bf8aade5 | ||
|
|
0172d6e892 | ||
|
|
bcb7351a90 | ||
|
|
c71a46ce9d | ||
|
|
91dd7799ef | ||
|
|
3682e253a7 | ||
|
|
66ecbb4d09 | ||
|
|
f041b6125b | ||
|
|
a4f2bab3d7 | ||
|
|
56bcfa5c87 |
2
.gitattributes
vendored
@@ -4,3 +4,5 @@ eventemitter2.js linguist-vendored
|
||||
ros3d.js linguist-vendored
|
||||
three.min.js linguist-vendored
|
||||
aruco_pose/vendor/* linguist-vendored
|
||||
blockly/* linguist-vendored
|
||||
highlight/* linguist-vendored
|
||||
|
||||
2
.gitignore
vendored
@@ -4,3 +4,5 @@
|
||||
node_modules/
|
||||
_book/
|
||||
package-lock.json
|
||||
clover_blocks/programs/*.*
|
||||
!clover_blocks/programs/examples/*
|
||||
|
||||
@@ -22,6 +22,7 @@
|
||||
"ROS Kinetic",
|
||||
"ROS Melodic",
|
||||
"OpenCV",
|
||||
"OpenVPN",
|
||||
"Gazebo",
|
||||
"GitHub",
|
||||
"FPV",
|
||||
@@ -106,7 +107,9 @@
|
||||
"UDP",
|
||||
"QR",
|
||||
"Li-ion",
|
||||
"Nvidia"
|
||||
"Nvidia",
|
||||
"VirtualBox",
|
||||
"VMware"
|
||||
],
|
||||
"code_blocks": false
|
||||
},
|
||||
|
||||
54
.travis.yml
@@ -7,10 +7,10 @@ env:
|
||||
global:
|
||||
- DOCKER="sfalexrog/img-tool:qemu-update"
|
||||
- TARGET_REPO="https://github.com/${TRAVIS_REPO_SLUG}.git"
|
||||
- if [[ -z ${TRAVIS_TAG} ]]; then IMAGE_VERSION="${TRAVIS_COMMIT}}"; else IMAGE_VERSION="${TRAVIS_TAG}"; fi
|
||||
- IMAGE_VERSION=${TRAVIS_TAG:-${TRAVIS_COMMIT:0:7}}
|
||||
- IMAGE_NAME="$(basename -s '.git' ${TARGET_REPO})_${IMAGE_VERSION}.img"
|
||||
git:
|
||||
depth: 50
|
||||
depth: 1
|
||||
jobs:
|
||||
fast_finish: true
|
||||
include:
|
||||
@@ -36,12 +36,13 @@ jobs:
|
||||
fi
|
||||
before_cache:
|
||||
- cp images/*.zip imgcache
|
||||
after_success:
|
||||
- sudo chmod -R 777 *
|
||||
- cd images && zip -9 ${IMAGE_NAME}.zip ${IMAGE_NAME} && stat --printf="Compressed image size:%s\n" ${IMAGE_NAME}.zip
|
||||
before_deploy:
|
||||
# Set up git user name and tag this commit
|
||||
- git config --local user.name "goldarte"
|
||||
- git config --local user.email "goldartt@gmail.com"
|
||||
- sudo chmod -R 777 *
|
||||
- cd images && zip ${IMAGE_NAME}.zip ${IMAGE_NAME}
|
||||
deploy:
|
||||
provider: releases
|
||||
token: ${GITHUB_OAUTH_TOKEN}
|
||||
@@ -73,8 +74,11 @@ jobs:
|
||||
node_js:
|
||||
- "10"
|
||||
before_script:
|
||||
- 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
|
||||
- npm install gitbook-cli -g
|
||||
- npm install markdownlint-cli -g
|
||||
- npm install svgexport -g
|
||||
- gitbook -V
|
||||
- markdownlint -V
|
||||
script:
|
||||
@@ -83,26 +87,25 @@ jobs:
|
||||
- ./check_unused_assets.py
|
||||
- gitbook install
|
||||
- gitbook build
|
||||
# deploy:
|
||||
# provider: pages
|
||||
# local_dir: _book
|
||||
# skip_cleanup: true
|
||||
# token: ${GITHUB_OAUTH_TOKEN}
|
||||
# keep_history: true
|
||||
# target_branch: master
|
||||
# repo: CopterExpress/clover.coex.tech
|
||||
# fqdn: clover.coex.tech
|
||||
# verbose: true
|
||||
# on:
|
||||
# branch: master
|
||||
- stage: Annotate
|
||||
name: Auto-generate changelog
|
||||
language: python
|
||||
python: 3.6
|
||||
install:
|
||||
- pip install GitPython PyGithub
|
||||
script:
|
||||
- PYTHONUNBUFFERED=1 python ./gen_changelog.py
|
||||
- for i in 1 2 3 4; do gitbook pdf ./ _book/clover.pdf && break || sleep 1; done
|
||||
- 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:
|
||||
provider: pages
|
||||
local_dir: _book
|
||||
skip_cleanup: true
|
||||
token: ${GITHUB_OAUTH_TOKEN}
|
||||
keep_history: true
|
||||
target_branch: master
|
||||
repo: CopterExpress/clover.coex.tech
|
||||
fqdn: clover.coex.tech
|
||||
verbose: true
|
||||
on:
|
||||
branch: master
|
||||
- stage: Build
|
||||
name: Editorconfig-lint
|
||||
language: generic
|
||||
@@ -110,10 +113,9 @@ jobs:
|
||||
- wget https://github.com/okalachev/editorconfig-checker/releases/download/1.2.1-disable-spaces-amount/ec-linux-amd64
|
||||
- chmod +x ec-linux-amd64
|
||||
script:
|
||||
- ./ec-linux-amd64 -spaces-after-tabs -e "roslib.js|ros3d.js|eventemitter2.js|draw.cpp|BinUtils.swift|\.idea|apps/android/app|Assets.xcassets|test_parser_pass.txt|test_node_failure.txt|aruco_pose/vendor|\.stl|\.dxf"
|
||||
- ./ec-linux-amd64 -spaces-after-tabs -e "roslib.js|ros3d.js|eventemitter2.js|draw.cpp|BinUtils.swift|\.idea|apps/android/app|blockly/|clover_blocks/programs/|highlight/|python.js|Assets.xcassets|test_parser_pass.txt|test_node_failure.txt|aruco_pose/vendor|\.stl|\.dxf|\.dae"
|
||||
stages:
|
||||
- Build
|
||||
- Annotate
|
||||
# More info there
|
||||
# https://github.com/travis-ci/travis-ci/issues/6893
|
||||
# https://docs.travis-ci.com/user/customizing-the-build/
|
||||
|
||||
12
README.md
@@ -1,12 +1,14 @@
|
||||
# COEX Clover Drone Kit
|
||||
# clover🍀: create autonomous drones easily
|
||||
|
||||
<img src="docs/assets/clever4-front-white.png" align="right" width="400px" alt="Clover Drone">
|
||||
<img src="docs/assets/clover42-main.png" align="right" width="400px" alt="COEX Clover Drone">
|
||||
|
||||
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.
|
||||
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.
|
||||
|
||||
The main documentation is available [on Gitbook](https://clover.coex.tech/).
|
||||
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.
|
||||
|
||||
Official website: <a href="https://coex.tech/clover">coex.tech/clover</a>.
|
||||
The main documentation is available at [https://clover.coex.tech](https://clover.coex.tech/). Official website: [coex.tech/clover](https://coex.tech/clover).
|
||||
|
||||
[__Support us on Kickstarter!__](https://www.kickstarter.com/projects/copterexpress/cloverdrone)
|
||||
|
||||
## Video compilation
|
||||
|
||||
|
||||
0
apps/CATKIN_IGNORE
Normal file
8
aruco_pose/CHANGELOG.rst
Normal file
@@ -0,0 +1,8 @@
|
||||
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||
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
|
||||
@@ -8,6 +8,8 @@ p = cv2.aruco.DetectorParameters_create()
|
||||
|
||||
gen = ParameterGenerator()
|
||||
|
||||
gen.add("enabled", bool_t, 0, "if detection enabled", True)
|
||||
|
||||
gen.add("adaptiveThreshConstant", double_t, 0,
|
||||
"Constant for adaptive thresholding before finding contours",
|
||||
p.adaptiveThreshConstant, 0, 100)
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
<?xml version="1.0"?>
|
||||
<package format="2">
|
||||
<name>aruco_pose</name>
|
||||
<version>0.0.1</version>
|
||||
<version>0.21.1</version>
|
||||
<description>Positioning with ArUco markers</description>
|
||||
|
||||
<maintainer email="okalachev@gmail.com">Oleg Kalachev</maintainer>
|
||||
|
||||
@@ -62,6 +62,7 @@ private:
|
||||
std::unique_ptr<tf2_ros::Buffer> tf_buffer_;
|
||||
std::unique_ptr<tf2_ros::TransformListener> tf_listener_;
|
||||
std::shared_ptr<dynamic_reconfigure::Server<aruco_pose::DetectorConfig>> dyn_srv_;
|
||||
bool enabled_ = true;
|
||||
cv::Ptr<cv::aruco::Dictionary> dictionary_;
|
||||
cv::Ptr<cv::aruco::DetectorParameters> parameters_;
|
||||
image_transport::Publisher debug_pub_;
|
||||
@@ -128,6 +129,8 @@ public:
|
||||
private:
|
||||
void imageCallback(const sensor_msgs::ImageConstPtr& msg, const sensor_msgs::CameraInfoConstPtr &cinfo)
|
||||
{
|
||||
if (!enabled_) return;
|
||||
|
||||
Mat image = cv_bridge::toCvShare(msg, "bgr8")->image;
|
||||
|
||||
vector<int> ids;
|
||||
@@ -356,6 +359,7 @@ private:
|
||||
|
||||
void paramCallback(aruco_pose::DetectorConfig &config, uint32_t level)
|
||||
{
|
||||
enabled_ = config.enabled;
|
||||
parameters_->adaptiveThreshConstant = config.adaptiveThreshConstant;
|
||||
parameters_->adaptiveThreshWinSizeMin = config.adaptiveThreshWinSizeMin;
|
||||
parameters_->adaptiveThreshWinSizeMax = config.adaptiveThreshWinSizeMax;
|
||||
|
||||
@@ -13,7 +13,7 @@
|
||||
Generate map file for aruco_map nodelet.
|
||||
|
||||
Usage:
|
||||
genmap.py <length> <x> <y> <dist_x> <dist_y> [<first>] [--top-left | --bottom-left]
|
||||
genmap.py <length> <x> <y> <dist_x> <dist_y> [<first>] [<x0>] [<y0>] [--top-left | --bottom-left]
|
||||
genmap.py (-h | --help)
|
||||
|
||||
Options:
|
||||
@@ -23,6 +23,8 @@ Options:
|
||||
<dist_x> Distance between markers along X axis
|
||||
<dist_y> Distance between markers along Y axis
|
||||
<first> First marker ID [default: 0]
|
||||
<x0> X 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)
|
||||
--bottom-left First marker is on bottom-left
|
||||
|
||||
@@ -39,20 +41,22 @@ arguments = docopt(__doc__)
|
||||
|
||||
length = float(arguments['<length>'])
|
||||
first = int(arguments['<first>'] if arguments['<first>'] is not None else 0)
|
||||
x0 = float(arguments['<x0>'] if arguments['<x0>'] is not None else 0)
|
||||
y0 = float(arguments['<y0>'] if arguments['<y0>'] is not None else 0)
|
||||
markers_x = int(arguments['<x>'])
|
||||
markers_y = int(arguments['<y>'])
|
||||
dist_x = float(arguments['<dist_x>'])
|
||||
dist_y = float(arguments['<dist_y>'])
|
||||
bottom_left = arguments['--bottom-left']
|
||||
|
||||
max_y = (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')
|
||||
for y in range(markers_y):
|
||||
for x in range(markers_x):
|
||||
pos_x = x * dist_x
|
||||
pos_y = y * dist_y
|
||||
pos_x = x0 + x * dist_x
|
||||
pos_y = y0 + y * dist_y
|
||||
if not bottom_left:
|
||||
pos_y = max_y - pos_y
|
||||
print('{}\t{}\t{}\t{}\t{}\t{}\t{}\t{}\t'.format(first, length, pos_x, pos_y, 0, 0, 0, 0))
|
||||
print('{}\t{}\t{}\t{}\t{}\t{}\t{}\t{}'.format(first, length, pos_x, pos_y, 0, 0, 0, 0))
|
||||
first += 1
|
||||
|
||||
@@ -9,6 +9,7 @@
|
||||
"richquotes@https://github.com/okalachev/gitbook-plugin-richquotes.git",
|
||||
"yametrika",
|
||||
"anchors",
|
||||
"collapsible-menu",
|
||||
"validate-links",
|
||||
"bulk-redirect@https://github.com/okalachev/gitbook-plugin-bulk-redirect.git",
|
||||
"sitemap@https://github.com/okalachev/plugin-sitemap.git",
|
||||
|
||||
34
builder/assets/avahi-services/sftp-ssh.service
Normal file
@@ -0,0 +1,34 @@
|
||||
<?xml version="1.0" standalone='no'?><!--*-nxml-*-->
|
||||
<!DOCTYPE service-group SYSTEM "avahi-service.dtd">
|
||||
|
||||
<!--
|
||||
This file is part of avahi.
|
||||
|
||||
avahi is free software; you can redistribute it and/or modify it
|
||||
under the terms of the GNU Lesser General Public License as
|
||||
published by the Free Software Foundation; either version 2 of the
|
||||
License, or (at your option) any later version.
|
||||
|
||||
avahi is distributed in the hope that it will be useful, but
|
||||
WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU Lesser General Public
|
||||
License along with avahi; if not, write to the Free Software
|
||||
Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
|
||||
02111-1307 USA.
|
||||
-->
|
||||
|
||||
<!-- See avahi.service(5) for more information about this configuration file -->
|
||||
|
||||
<service-group>
|
||||
|
||||
<name replace-wildcards="yes">%h</name>
|
||||
|
||||
<service>
|
||||
<type>_sftp-ssh._tcp</type>
|
||||
<port>22</port>
|
||||
</service>
|
||||
|
||||
</service-group>
|
||||
@@ -1,4 +1,4 @@
|
||||
# Information: https://clover.coex.tech/en/aruco.html
|
||||
# Information: https://clover.coex.tech/aruco
|
||||
|
||||
import rospy
|
||||
from clover import srv
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
# Information: https://clover.coex.tech/en/leds.html
|
||||
# Information: https://clover.coex.tech/led
|
||||
|
||||
import rospy
|
||||
from clover.srv import SetLEDEffect
|
||||
@@ -7,19 +7,25 @@ rospy.init_node('leds')
|
||||
|
||||
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
|
||||
rospy.sleep(2)
|
||||
|
||||
print('Fill green')
|
||||
set_effect(r=0, g=100, b=0) # fill strip with green color
|
||||
rospy.sleep(2)
|
||||
|
||||
print('Fade to blue')
|
||||
set_effect(effect='fade', r=0, g=0, b=255) # fade to blue color
|
||||
rospy.sleep(2)
|
||||
|
||||
print('Flash red')
|
||||
set_effect(effect='flash', r=255, g=0, b=0) # flash twice with red color
|
||||
rospy.sleep(5)
|
||||
rospy.sleep(2)
|
||||
|
||||
print('Blink white')
|
||||
set_effect(effect='blink', r=255, g=255, b=255) # blink with white color
|
||||
rospy.sleep(5)
|
||||
|
||||
print('Rainbow')
|
||||
set_effect(effect='rainbow') # show rainbow
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
# Information: https://clover.coex.tech/en/snippets.html#block-nav
|
||||
# Information: https://clover.coex.tech/en/snippets.html#navigate_wait
|
||||
|
||||
import math
|
||||
import rospy
|
||||
|
||||
@@ -65,7 +65,7 @@ echo_stamp "#6 Turn on UART"
|
||||
# https://github.com/RPi-Distro/raspi-config/pull/75
|
||||
/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 dtoverlay pi3-disable-bt /boot/config.txt
|
||||
echo dtoverlay=pi3-disable-bt >> /boot/config.txt
|
||||
systemctl disable hciuart.service
|
||||
|
||||
# After adding to Raspbian OS
|
||||
@@ -79,4 +79,10 @@ if ! grep -q "^bcm2835-v4l2" /etc/modules;
|
||||
then printf "bcm2835-v4l2\n" >> /etc/modules
|
||||
fi
|
||||
|
||||
echo_stamp "#8 End of configure hardware interfaces"
|
||||
echo_stamp "#8 Check if Compute Module 4"
|
||||
if grep -q "Compute Module 4" "/proc/device-tree/model"; then
|
||||
echo_stamp "Enable USB on Compute Module 4"
|
||||
echo "dtoverlay=dwc2,dr_mode=host" >> /boot/config.txt
|
||||
fi
|
||||
|
||||
echo_stamp "#9 End of configure hardware interfaces"
|
||||
|
||||
@@ -20,7 +20,7 @@
|
||||
# Example:
|
||||
# DocumentRoot /home/krypton/htdocs
|
||||
|
||||
DocumentRoot /home/pi/catkin_ws/src/clover/clover/www
|
||||
DocumentRoot /home/pi/.ros/www
|
||||
|
||||
# Redirect:
|
||||
# ---------
|
||||
|
||||
@@ -15,7 +15,7 @@
|
||||
|
||||
set -e # Exit immidiately on non-zero result
|
||||
|
||||
SOURCE_IMAGE="https://downloads.raspberrypi.org/raspbian_lite/images/raspbian_lite-2020-02-14/2020-02-13-raspbian-buster-lite.zip"
|
||||
SOURCE_IMAGE="https://downloads.raspberrypi.org/raspios_lite_armhf/images/raspios_lite_armhf-2021-01-12/2021-01-11-raspios-buster-armhf-lite.zip"
|
||||
|
||||
export DEBIAN_FRONTEND=${DEBIAN_FRONTEND:='noninteractive'}
|
||||
export LANG=${LANG:='C.UTF-8'}
|
||||
@@ -105,9 +105,11 @@ ${BUILDER_DIR}/image-chroot.sh ${IMAGE_PATH} copy ${SCRIPTS_DIR}'/assets/monkey.
|
||||
# software install
|
||||
${BUILDER_DIR}/image-chroot.sh ${IMAGE_PATH} exec ${SCRIPTS_DIR}'/image-software.sh'
|
||||
# examples
|
||||
${BUILDER_DIR}/image-chroot.sh ${IMAGE_PATH} copy ${SCRIPTS_DIR}'/assets/examples' '/home/pi/'
|
||||
${BUILDER_DIR}/image-chroot.sh ${IMAGE_PATH} copy ${SCRIPTS_DIR}'/assets/examples' '/home/pi/' # TODO: symlink?
|
||||
# network setup
|
||||
${BUILDER_DIR}/image-chroot.sh ${IMAGE_PATH} exec ${SCRIPTS_DIR}'/image-network.sh'
|
||||
# avahi setup
|
||||
${BUILDER_DIR}/image-chroot.sh ${IMAGE_PATH} copy ${SCRIPTS_DIR}'/assets/avahi-services/sftp-ssh.service' '/etc/avahi/services'
|
||||
|
||||
# If RPi then use a one thread to build a ROS package on RPi, else use all
|
||||
[[ $(arch) == 'armv7l' ]] && NUMBER_THREADS=1 || NUMBER_THREADS=$(nproc --all)
|
||||
|
||||
@@ -60,4 +60,25 @@ domain-needed
|
||||
quiet-dhcp6
|
||||
EOF
|
||||
|
||||
echo_stamp "#4 End of network installation"
|
||||
echo_stamp "#4 Build the RTL8814AU Wi-Fi adapter driver"
|
||||
wget http://archive.raspberrypi.org/debian/pool/main/r/raspberrypi-firmware/raspberrypi-kernel-headers_1.20210108-1_armhf.deb
|
||||
dpkg -i raspberrypi-kernel-headers_1.20210108-1_armhf.deb
|
||||
cd /home/pi
|
||||
git clone https://github.com/aircrack-ng/rtl8812au.git --depth=1
|
||||
cd rtl8812au
|
||||
echo kernel version: $(uname -r)
|
||||
echo kernel version from procfs: $(cat /proc/version)
|
||||
echo version: $(git describe --tags --always)
|
||||
sed -i 's/CONFIG_PLATFORM_I386_PC = y/CONFIG_PLATFORM_I386_PC = n/g' Makefile # https://github.com/aircrack-ng/rtl8812au#for-raspberry-rpi
|
||||
sed -i 's/CONFIG_PLATFORM_ARM_RPI = n/CONFIG_PLATFORM_ARM_RPI = y/g' Makefile
|
||||
# sed -i 's/CONFIG_PLATFORM_ARM64_RPI = n/CONFIG_PLATFORM_ARM64_RPI = y/g' Makefile
|
||||
apt-cache policy raspberrypi-kernel-headers
|
||||
# apt-get install -y raspberrypi-kernel-headers=1.20210108 dkms
|
||||
apt-get install -y dkms
|
||||
ls /lib/modules
|
||||
echo make
|
||||
make KERNEL_VER=5.4.83-v7l+ KVER=5.4.83-v7l+ # TODO: determine kernel version from fs
|
||||
echo make install
|
||||
make install KERNEL_VER=5.4.83-v7l+ KVER=5.4.83-v7l+
|
||||
|
||||
echo_stamp "#5 End of network installation"
|
||||
|
||||
@@ -74,31 +74,24 @@ my_travis_retry rosdep update
|
||||
echo_stamp "Populate rosdep for ROS user"
|
||||
my_travis_retry sudo -u pi rosdep update
|
||||
|
||||
resolve_rosdep() {
|
||||
# TEMPLATE: resolve_rosdep <CATKIN_PATH> <ROS_DISTRO> <OS_DISTRO> <OS_VERSION>
|
||||
CATKIN_PATH=$1
|
||||
ROS_DISTRO='melodic'
|
||||
OS_DISTRO='debian'
|
||||
OS_VERSION='buster'
|
||||
|
||||
echo_stamp "Installing dependencies apps with rosdep in ${CATKIN_PATH}"
|
||||
cd ${CATKIN_PATH}
|
||||
my_travis_retry rosdep install -y --from-paths src --ignore-src --rosdistro ${ROS_DISTRO} --os=${OS_DISTRO}:${OS_VERSION}
|
||||
}
|
||||
|
||||
export ROS_IP='127.0.0.1' # needed for running tests
|
||||
|
||||
echo_stamp "Reconfiguring Clover repository for simplier unshallowing"
|
||||
cd /home/pi/catkin_ws/src/clover
|
||||
git config remote.origin.fetch "+refs/heads/*:refs/remotes/origin/*"
|
||||
# echo_stamp "Reconfiguring Clover repository for simplier unshallowing" # TODO: bring back
|
||||
# cd /home/pi/catkin_ws/src/clover
|
||||
# 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
|
||||
|
||||
echo_stamp "Build and install Clover"
|
||||
cd /home/pi/catkin_ws
|
||||
resolve_rosdep $(pwd)
|
||||
# Don't try to install gazebo_ros
|
||||
my_travis_retry rosdep install -y --from-paths src --ignore-src --rosdistro melodic --os=debian:buster \
|
||||
--skip-keys=gazebo_ros --skip-keys=gazebo_plugins
|
||||
my_travis_retry pip install wheel
|
||||
my_travis_retry pip install -r /home/pi/catkin_ws/src/clover/clover/requirements.txt
|
||||
source /opt/ros/melodic/setup.bash
|
||||
catkin_make -j2 -DCMAKE_BUILD_TYPE=Release
|
||||
# Don't build simulation plugins for actual drone
|
||||
catkin_make -j2 -DCMAKE_BUILD_TYPE=Release -DCATKIN_BLACKLIST_PACKAGES=clover_gazebo_plugins
|
||||
|
||||
echo_stamp "Install clever package (for backwards compatibility)"
|
||||
cd /home/pi/catkin_ws/src/clover/builder/assets/clever
|
||||
@@ -113,7 +106,7 @@ 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
|
||||
|
||||
echo_stamp "Installing additional ROS packages"
|
||||
apt-get install -y --no-install-recommends \
|
||||
my_travis_retry apt-get install -y --no-install-recommends \
|
||||
ros-melodic-dynamic-reconfigure \
|
||||
ros-melodic-compressed-image-transport \
|
||||
ros-melodic-rosbridge-suite \
|
||||
@@ -139,11 +132,13 @@ catkin_make run_tests #&& catkin_test_results
|
||||
echo_stamp "Change permissions for 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"
|
||||
cat << EOF >> /home/pi/.bashrc
|
||||
LANG='C.UTF-8'
|
||||
LC_ALL='C.UTF-8'
|
||||
ROS_DISTRO='melodic'
|
||||
export ROS_HOSTNAME=\`hostname\`.local
|
||||
source /opt/ros/melodic/setup.bash
|
||||
source /home/pi/catkin_ws/devel/setup.bash
|
||||
|
||||
@@ -80,8 +80,10 @@ echo_stamp "Update apt cache"
|
||||
apt-get update
|
||||
# && apt upgrade -y
|
||||
|
||||
# Let's retry fetching those packages several times, just in case
|
||||
echo_stamp "Software installing"
|
||||
apt-get install --no-install-recommends -y \
|
||||
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 \
|
||||
unzip \
|
||||
zip \
|
||||
ipython \
|
||||
@@ -93,8 +95,8 @@ lsof \
|
||||
git \
|
||||
dnsmasq \
|
||||
tmux \
|
||||
tree \
|
||||
vim \
|
||||
cmake \
|
||||
libjpeg8 \
|
||||
tcpdump \
|
||||
ltrace \
|
||||
@@ -109,15 +111,12 @@ libffi-dev \
|
||||
monkey \
|
||||
pigpio python-pigpio python3-pigpio \
|
||||
i2c-tools \
|
||||
espeak espeak-data python-espeak \
|
||||
ntpdate \
|
||||
python-dev \
|
||||
python3-dev \
|
||||
python-systemd \
|
||||
mjpg-streamer \
|
||||
python3-opencv \
|
||||
&& echo_stamp "Everything was installed!" "SUCCESS" \
|
||||
|| (echo_stamp "Some packages wasn't installed!" "ERROR"; exit 1)
|
||||
python3-opencv
|
||||
|
||||
# Deny byobu to check available updates
|
||||
sed -i "s/updates_available//" /usr/share/byobu/status/status
|
||||
@@ -125,9 +124,10 @@ sed -i "s/updates_available//" /usr/share/byobu/status/status
|
||||
|
||||
echo_stamp "Installing pip"
|
||||
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
|
||||
python get-pip.py
|
||||
rm get-pip.py
|
||||
python get-pip2.py
|
||||
rm get-pip.py get-pip2.py
|
||||
#my_travis_retry pip install --upgrade pip
|
||||
#my_travis_retry pip3 install --upgrade pip
|
||||
|
||||
@@ -137,6 +137,7 @@ pip3 --version
|
||||
|
||||
echo_stamp "Install and enable Butterfly (web terminal)"
|
||||
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 butterfly
|
||||
my_travis_retry pip3 install butterfly[systemd]
|
||||
|
||||
@@ -5,7 +5,7 @@ set -e
|
||||
# Step 1: Install pip
|
||||
apt update
|
||||
apt install -y curl
|
||||
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-pip.py
|
||||
python ./get-pip.py
|
||||
|
||||
# Step 1.5: Add deb.coex.tech to apt
|
||||
|
||||
@@ -25,7 +25,7 @@ import pymavlink
|
||||
from pymavlink import mavutil
|
||||
import rpi_ws281x
|
||||
import pigpio
|
||||
from espeak import espeak
|
||||
# from espeak import espeak
|
||||
from pyzbar import pyzbar
|
||||
|
||||
print cv2.getBuildInformation()
|
||||
|
||||
@@ -32,7 +32,7 @@ monkey --version
|
||||
pigpiod -v
|
||||
i2cdetect -V
|
||||
butterfly -h
|
||||
espeak --version
|
||||
# espeak --version
|
||||
mjpg_streamer --version
|
||||
|
||||
# ros stuff
|
||||
@@ -43,6 +43,8 @@ rosversion aruco_pose
|
||||
rosversion vl53l1x
|
||||
rosversion mavros
|
||||
rosversion mavros_extras
|
||||
rosversion ws281x
|
||||
rosversion led_msgs
|
||||
rosversion dynamic_reconfigure
|
||||
rosversion tf2_web_republisher
|
||||
rosversion compressed_image_transport
|
||||
|
||||
@@ -4,7 +4,9 @@ import os
|
||||
import sys
|
||||
import subprocess
|
||||
|
||||
EXCLUDE = ('clever4-front-white.png', '.DS_Store', 'clever4-front-black-large.png')
|
||||
EXCLUDE = ('clever4-front-white.png', 'clever4-front-white-large.png', '.DS_Store',
|
||||
'clever4-front-black-large.png','clover42-black.png')
|
||||
|
||||
code = 0
|
||||
|
||||
os.chdir('./docs')
|
||||
|
||||
8
clover/CHANGELOG.rst
Normal file
@@ -0,0 +1,8 @@
|
||||
^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||
Changelog for package clover
|
||||
^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||
|
||||
0.21.1 (2020-11-17)
|
||||
-------------------
|
||||
* First release of clover package to ROS
|
||||
* Contributors: Alexey Rogachevskiy, Arthur Golubtsov, Oleg Kalachev
|
||||
@@ -166,13 +166,14 @@ add_library(${PROJECT_NAME}
|
||||
## The recommended prefix ensures that target names across packages don't collide
|
||||
add_executable(simple_offboard src/simple_offboard.cpp)
|
||||
|
||||
add_executable(rc src/rc.cpp)
|
||||
# PX4 already has rc and led targets, so we prefix ours with clover_
|
||||
add_executable(clover_rc src/rc.cpp)
|
||||
|
||||
add_executable(camera_markers src/camera_markers.cpp)
|
||||
|
||||
add_executable(vpe_publisher src/vpe_publisher.cpp)
|
||||
|
||||
add_executable(led src/led.cpp)
|
||||
add_executable(clover_led src/led.cpp)
|
||||
|
||||
add_executable(shell src/shell.cpp)
|
||||
|
||||
@@ -181,19 +182,24 @@ target_link_libraries(simple_offboard
|
||||
${GeographicLib_LIBRARIES}
|
||||
)
|
||||
|
||||
target_link_libraries(rc ${catkin_LIBRARIES})
|
||||
# Don't change actual binary names
|
||||
set_target_properties(clover_rc PROPERTIES OUTPUT_NAME rc)
|
||||
|
||||
set_target_properties(clover_led PROPERTIES OUTPUT_NAME led)
|
||||
|
||||
target_link_libraries(clover_rc ${catkin_LIBRARIES})
|
||||
|
||||
target_link_libraries(camera_markers ${catkin_LIBRARIES})
|
||||
|
||||
target_link_libraries(vpe_publisher ${catkin_LIBRARIES})
|
||||
|
||||
target_link_libraries(led ${catkin_LIBRARIES})
|
||||
target_link_libraries(clover_led ${catkin_LIBRARIES})
|
||||
|
||||
target_link_libraries(shell ${catkin_LIBRARIES})
|
||||
|
||||
add_dependencies(simple_offboard ${PROJECT_NAME}_generate_messages_cpp)
|
||||
|
||||
add_dependencies(led ${PROJECT_NAME}_generate_messages_cpp)
|
||||
add_dependencies(clover_led ${PROJECT_NAME}_generate_messages_cpp)
|
||||
|
||||
add_dependencies(shell ${PROJECT_NAME}_generate_messages_cpp)
|
||||
|
||||
|
||||
@@ -44,30 +44,12 @@ Alternatively you may change the `fcu_url` property in `mavros.launch` file to p
|
||||
|
||||
## Running
|
||||
|
||||
Enable systemd service `roscore` (if not running):
|
||||
|
||||
```bash
|
||||
sudo systemctl enable /home/<username>/catkin_ws/src/clover/builder/assets/roscore.service
|
||||
sudo systemctl start roscore
|
||||
```
|
||||
|
||||
To start connection to SITL, use:
|
||||
|
||||
```bash
|
||||
roslaunch clover sitl.launch
|
||||
```
|
||||
|
||||
To start connection to the flight controller, use:
|
||||
|
||||
```bash
|
||||
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`.
|
||||
|
||||
Also, you can enable and start the systemd service:
|
||||
|
||||
```bash
|
||||
sudo systemctl enable /home/<username>/catkin_ws/src/clover/deploy/clover.service
|
||||
sudo systemctl start clover
|
||||
```
|
||||
|
||||
@@ -10,9 +10,12 @@
|
||||
<arg name="aruco" default="false"/>
|
||||
<arg name="rangefinder_vl53l1x" default="true"/>
|
||||
<arg name="led" default="true"/>
|
||||
<arg name="blocks" 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 -->
|
||||
|
||||
<!-- log formatting -->
|
||||
<env name="ROSCONSOLE_FORMAT" value="[${severity}] [${time}]: ${logger}: ${message}"/>
|
||||
|
||||
@@ -53,10 +56,13 @@
|
||||
<param name="reference_frames/body" value="map"/>
|
||||
<param name="reference_frames/base_link" value="map"/>
|
||||
<param name="reference_frames/navigate_target" value="map"/>
|
||||
<param name="reference_frames/main_camera_optical" value="map"/>
|
||||
</node>
|
||||
|
||||
<!-- main camera -->
|
||||
<include file="$(find clover)/launch/main_camera.launch" if="$(arg main_camera)"/>
|
||||
<include file="$(find clover)/launch/main_camera.launch" if="$(arg main_camera)">
|
||||
<arg name="simulator" value="$(arg simulator)"/>
|
||||
</include>
|
||||
|
||||
<!-- rosbridge -->
|
||||
<include file="$(find rosbridge_server)/launch/rosbridge_websocket.launch" if="$(eval rosbridge or rc)"/>
|
||||
@@ -65,14 +71,19 @@
|
||||
<node name="tf2_web_republisher" pkg="tf2_web_republisher" type="tf2_web_republisher" output="screen" if="$(arg rosbridge)"/>
|
||||
|
||||
<!-- vl53l1x ToF rangefinder -->
|
||||
<node name="rangefinder" pkg="vl53l1x" type="vl53l1x_node" output="screen" if="$(arg rangefinder_vl53l1x)">
|
||||
<node name="rangefinder" pkg="vl53l1x" type="vl53l1x_node" output="screen" if="$(eval rangefinder_vl53l1x and not simulator)">
|
||||
<param name="frame_id" value="rangefinder"/>
|
||||
<param name="min_signal" value="0.4"/>
|
||||
<param name="pass_statuses" type="yaml" value="[0, 6, 7, 11]"/>
|
||||
</node>
|
||||
|
||||
<!-- led strip -->
|
||||
<include file="$(find clover)/launch/led.launch" if="$(arg led)"/>
|
||||
<include file="$(find clover)/launch/led.launch" if="$(arg led)">
|
||||
<arg name="simulator" value="$(arg simulator)"/>
|
||||
</include>
|
||||
|
||||
<!-- Clover Blocks -->
|
||||
<node name="clover_blocks" pkg="clover_blocks" type="clover_blocks" output="screen" if="$(arg blocks)"/>
|
||||
|
||||
<!-- rc backend -->
|
||||
<node name="rc" pkg="clover" type="rc" output="screen" if="$(arg rc)" clear_params="true">
|
||||
@@ -82,4 +93,9 @@
|
||||
|
||||
<!-- Shell access through ROS service -->
|
||||
<node name="shell" pkg="clover" type="shell" output="screen" if="$(arg shell)"/>
|
||||
|
||||
<!-- Update static directory -->
|
||||
<node pkg="roswww_static" name="roswww_static" type="main.py" clear_params="true">
|
||||
<param name="default_package" value="clover"/>
|
||||
</node>
|
||||
</launch>
|
||||
|
||||
@@ -2,13 +2,17 @@
|
||||
<arg name="ws281x" default="true"/>
|
||||
<arg name="led_effect" default="true"/>
|
||||
<arg name="led_notify" default="true"/>
|
||||
<arg name="led_count" default="72"/>
|
||||
<arg name="gpio_pin" default="21"/>
|
||||
|
||||
<arg name="simulator" default="false"/>
|
||||
|
||||
<!-- For additional help go to https://clover.coex.tech/led -->
|
||||
|
||||
<!-- ws281x led strip driver -->
|
||||
<node pkg="ws281x" name="led" type="ws281x_node" clear_params="true" output="screen" if="$(arg ws281x)">
|
||||
<param name="led_count" value="58"/>
|
||||
<param name="gpio_pin" value="21"/>
|
||||
<node pkg="ws281x" name="led" type="ws281x_node" clear_params="true" output="screen" if="$(eval ws281x and not simulator)">
|
||||
<param name="led_count" value="$(arg led_count)"/>
|
||||
<param name="gpio_pin" value="$(arg gpio_pin)"/>
|
||||
<param name="brightness" value="64"/>
|
||||
<param name="strip_type" value="WS2811_STRIP_GRB"/>
|
||||
<param name="target_frequency" value="800000"/>
|
||||
@@ -31,7 +35,7 @@
|
||||
altctl: { r: 255, g: 255, b: 40 }
|
||||
posctl: { r: 50, g: 100, b: 220 }
|
||||
offboard: { r: 220, g: 20, b: 250 }
|
||||
low_battery: { threshold: 3.7, effect: blink_fast, r: 255, g: 0, b: 0 }
|
||||
low_battery: { threshold: 3.6, effect: blink_fast, r: 255, g: 0, b: 0 }
|
||||
error: { effect: flash, r: 255, g: 0, b: 0 }
|
||||
</rosparam>
|
||||
</node>
|
||||
|
||||
@@ -3,11 +3,14 @@
|
||||
|
||||
<arg name="direction_z" default="down"/> <!-- direction the camera points: down, up -->
|
||||
<arg name="direction_y" default="backward"/> <!-- direction the camera cable points: backward, forward -->
|
||||
<arg name="simulator" default="false"/>
|
||||
|
||||
<node if="$(eval direction_z == 'down' and direction_y == 'backward')" pkg="tf2_ros" type="static_transform_publisher" name="main_camera_frame" args="0.05 0 -0.07 -1.5707963 0 3.1415926 base_link main_camera_optical"/>
|
||||
<node if="$(eval direction_z == 'down' and direction_y == 'forward')" pkg="tf2_ros" type="static_transform_publisher" name="main_camera_frame" args="0.05 0 -0.07 1.5707963 0 3.1415926 base_link main_camera_optical"/>
|
||||
<node if="$(eval direction_z == 'up' and direction_y == 'backward')" pkg="tf2_ros" type="static_transform_publisher" name="main_camera_frame" args="0.05 0 0.07 1.5707963 0 0 base_link main_camera_optical"/>
|
||||
<node if="$(eval direction_z == 'up' and direction_y == 'forward')" pkg="tf2_ros" type="static_transform_publisher" name="main_camera_frame" args="0.05 0 0.07 -1.5707963 0 0 base_link main_camera_optical"/>
|
||||
<node if="$(eval direction_z == 'forward')" pkg="tf2_ros" type="static_transform_publisher" name="main_camera_frame" args="0.03 0 0.05 -1.5707963 0 -1.5707963 base_link main_camera_optical"/>
|
||||
<node if="$(eval direction_z == 'backward')" pkg="tf2_ros" type="static_transform_publisher" name="main_camera_frame" args="-0.03 0 0.05 1.5707963 0 -1.5707963 base_link main_camera_optical"/>
|
||||
|
||||
<!-- Template for custom camera orientation -->
|
||||
<!-- Camera position and orientation are represented by base_link -> main_camera_optical transform -->
|
||||
@@ -15,7 +18,7 @@
|
||||
<!-- <node pkg="tf2_ros" type="static_transform_publisher" name="main_camera_frame" args="0.05 0 -0.07 -1.5707963 0 3.1415926 base_link main_camera_optical"/> -->
|
||||
|
||||
<!-- camera node -->
|
||||
<node pkg="nodelet" type="nodelet" name="main_camera" args="load cv_camera/CvCameraNodelet nodelet_manager" clear_params="true">
|
||||
<node pkg="nodelet" type="nodelet" name="main_camera" args="load cv_camera/CvCameraNodelet nodelet_manager" clear_params="true" unless="$(arg simulator)">
|
||||
<param name="device_path" value="/dev/video0"/> <!-- v4l2 device -->
|
||||
<param name="frame_id" value="main_camera_optical"/>
|
||||
<param name="camera_info_url" value="file://$(find clover)/camera_info/fisheye_cam.yaml"/>
|
||||
|
||||
@@ -1,19 +0,0 @@
|
||||
<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"?>
|
||||
<package format="2">
|
||||
<name>clover</name>
|
||||
<version>0.0.1</version>
|
||||
<version>0.21.1</version>
|
||||
<description>The Clover package</description>
|
||||
|
||||
<maintainer email="okalachev@gmail.com">Oleg Kalachev</maintainer>
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
flask==1.1.1
|
||||
docopt==0.6.2
|
||||
geopy==1.11.0
|
||||
smbus2==0.2.1
|
||||
VL53L1X==0.0.2
|
||||
smbus2==0.3.0
|
||||
VL53L1X==0.0.5
|
||||
|
||||
@@ -701,7 +701,7 @@ def check_preflight_status():
|
||||
|
||||
@check('Network')
|
||||
def check_network():
|
||||
ros_hostname = os.environ.get('ROS_HOSTNAME').strip()
|
||||
ros_hostname = os.environ.get('ROS_HOSTNAME', '').strip()
|
||||
|
||||
if not ros_hostname:
|
||||
failure('no ROS_HOSTNAME is set')
|
||||
|
||||
@@ -36,6 +36,7 @@
|
||||
#include <mavros_msgs/Thrust.h>
|
||||
#include <mavros_msgs/State.h>
|
||||
#include <mavros_msgs/StatusText.h>
|
||||
#include <mavros_msgs/ManualControl.h>
|
||||
|
||||
#include <clover/GetTelemetry.h>
|
||||
#include <clover/Navigate.h>
|
||||
@@ -46,6 +47,7 @@
|
||||
#include <clover/SetRates.h>
|
||||
|
||||
using std::string;
|
||||
using std::isnan;
|
||||
using namespace geometry_msgs;
|
||||
using namespace sensor_msgs;
|
||||
using namespace clover;
|
||||
@@ -71,9 +73,10 @@ ros::Duration state_timeout;
|
||||
ros::Duration velocity_timeout;
|
||||
ros::Duration global_position_timeout;
|
||||
ros::Duration battery_timeout;
|
||||
ros::Duration manual_control_timeout;
|
||||
float default_speed;
|
||||
bool auto_release;
|
||||
bool land_only_in_offboard, nav_from_sp;
|
||||
bool land_only_in_offboard, nav_from_sp, check_kill_switch;
|
||||
std::map<string, string> reference_frames;
|
||||
|
||||
// Publishers
|
||||
@@ -121,6 +124,7 @@ enum { YAW, YAW_RATE, TOWARDS } setpoint_yaw_type;
|
||||
// Last received telemetry messages
|
||||
mavros_msgs::State state;
|
||||
mavros_msgs::StatusText statustext;
|
||||
mavros_msgs::ManualControl manual_control;
|
||||
PoseStamped local_position;
|
||||
TwistStamped velocity;
|
||||
NavSatFix global_position;
|
||||
@@ -417,8 +421,9 @@ void publish(const ros::Time stamp)
|
||||
}
|
||||
|
||||
if (setpoint_type == POSITION || setpoint_type == NAVIGATE || setpoint_type == NAVIGATE_GLOBAL) {
|
||||
position_msg.header.stamp = stamp;
|
||||
|
||||
if (setpoint_yaw_type == YAW || setpoint_yaw_type == TOWARDS) {
|
||||
position_msg.header.stamp = stamp;
|
||||
position_pub.publish(position_msg);
|
||||
|
||||
} else {
|
||||
@@ -484,6 +489,27 @@ void publishSetpoint(const ros::TimerEvent& event)
|
||||
publish(event.current_real);
|
||||
}
|
||||
|
||||
inline void checkManualControl()
|
||||
{
|
||||
if (!manual_control_timeout.isZero() && TIMEOUT(manual_control, manual_control_timeout)) {
|
||||
throw std::runtime_error("Manual control timeout, RC is switched off?");
|
||||
}
|
||||
|
||||
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
|
||||
uint8_t kill_switch = (manual_control.buttons & (0b11 << KILL_SWITCH_BIT)) >> KILL_SWITCH_BIT;
|
||||
|
||||
if (kill_switch == SWITCH_POS_ON)
|
||||
throw std::runtime_error("Kill switch is on");
|
||||
}
|
||||
}
|
||||
|
||||
inline void checkState()
|
||||
{
|
||||
if (TIMEOUT(state, state_timeout))
|
||||
@@ -506,25 +532,88 @@ bool serve(enum setpoint_type_t sp_type, float x, float y, float z, float vx, fl
|
||||
if (busy)
|
||||
throw std::runtime_error("Busy");
|
||||
|
||||
ENSURE_FINITE(x);
|
||||
ENSURE_FINITE(y);
|
||||
ENSURE_FINITE(z);
|
||||
ENSURE_FINITE(vx);
|
||||
ENSURE_FINITE(vy);
|
||||
ENSURE_FINITE(vz);
|
||||
ENSURE_FINITE(pitch);
|
||||
ENSURE_FINITE(roll);
|
||||
ENSURE_FINITE(pitch_rate);
|
||||
ENSURE_FINITE(roll_rate);
|
||||
ENSURE_FINITE(lat);
|
||||
ENSURE_FINITE(lon);
|
||||
ENSURE_FINITE(thrust);
|
||||
|
||||
busy = true;
|
||||
|
||||
// Checks
|
||||
checkState();
|
||||
|
||||
if (auto_arm) {
|
||||
checkManualControl();
|
||||
}
|
||||
|
||||
// default frame is local frame
|
||||
if (frame_id.empty())
|
||||
frame_id = local_frame;
|
||||
|
||||
// look up for reference frame
|
||||
auto search = reference_frames.find(frame_id);
|
||||
const string& reference_frame = search == reference_frames.end() ? frame_id : search->second;
|
||||
|
||||
// Serve "partial" commands
|
||||
|
||||
if (!auto_arm && std::isfinite(yaw) &&
|
||||
isnan(x) && isnan(y) && isnan(z) && isnan(vx) && isnan(vy) && isnan(vz) &&
|
||||
isnan(pitch) && isnan(roll) && isnan(thrust) &&
|
||||
isnan(lat) && isnan(lon)) {
|
||||
// change only the yaw
|
||||
if (setpoint_type == POSITION || setpoint_type == NAVIGATE || setpoint_type == NAVIGATE_GLOBAL || setpoint_type == VELOCITY) {
|
||||
if (!waitTransform(setpoint_position.header.frame_id, frame_id, stamp, transform_timeout))
|
||||
throw std::runtime_error("Can't transform from " + frame_id + " to " + setpoint_position.header.frame_id);
|
||||
|
||||
message = "Changing yaw only";
|
||||
|
||||
QuaternionStamped q;
|
||||
q.header.frame_id = frame_id;
|
||||
q.header.stamp = stamp;
|
||||
q.quaternion = tf::createQuaternionMsgFromYaw(yaw); // TODO: pitch=0, roll=0 is not totally correct
|
||||
setpoint_position.pose.orientation = tf_buffer.transform(q, setpoint_position.header.frame_id).quaternion;
|
||||
setpoint_yaw_type = YAW;
|
||||
goto publish_setpoint;
|
||||
} else {
|
||||
throw std::runtime_error("Setting yaw is possible only when position or velocity setpoints active");
|
||||
}
|
||||
}
|
||||
|
||||
if (!auto_arm && std::isfinite(yaw_rate) &&
|
||||
isnan(x) && isnan(y) && isnan(z) && isnan(vx) && isnan(vy) && isnan(vz) &&
|
||||
isnan(pitch) && isnan(roll) && isnan(yaw) && isnan(thrust) &&
|
||||
isnan(lat) && isnan(lon)) {
|
||||
// change only the yaw rate
|
||||
if (setpoint_type == POSITION || setpoint_type == NAVIGATE || setpoint_type == NAVIGATE_GLOBAL || setpoint_type == VELOCITY) {
|
||||
message = "Changing yaw rate only";
|
||||
|
||||
setpoint_yaw_type = YAW_RATE;
|
||||
setpoint_yaw_rate = yaw_rate;
|
||||
goto publish_setpoint;
|
||||
} else {
|
||||
throw std::runtime_error("Setting yaw rate is possible only when position or velocity setpoints active");
|
||||
}
|
||||
}
|
||||
|
||||
// Serve normal commands
|
||||
|
||||
if (sp_type == NAVIGATE || sp_type == POSITION) {
|
||||
ENSURE_FINITE(x);
|
||||
ENSURE_FINITE(y);
|
||||
ENSURE_FINITE(z);
|
||||
} else if (sp_type == NAVIGATE_GLOBAL) {
|
||||
ENSURE_FINITE(lat);
|
||||
ENSURE_FINITE(lon);
|
||||
ENSURE_FINITE(z);
|
||||
} else if (sp_type == VELOCITY) {
|
||||
ENSURE_FINITE(vx);
|
||||
ENSURE_FINITE(vy);
|
||||
ENSURE_FINITE(vz);
|
||||
} else if (sp_type == ATTITUDE) {
|
||||
ENSURE_FINITE(pitch);
|
||||
ENSURE_FINITE(roll);
|
||||
ENSURE_FINITE(thrust);
|
||||
} else if (sp_type == RATES) {
|
||||
ENSURE_FINITE(pitch_rate);
|
||||
ENSURE_FINITE(roll_rate);
|
||||
ENSURE_FINITE(thrust);
|
||||
}
|
||||
|
||||
if (sp_type == NAVIGATE || sp_type == NAVIGATE_GLOBAL) {
|
||||
if (TIMEOUT(local_position, local_position_timeout))
|
||||
throw std::runtime_error("No local position, check settings");
|
||||
@@ -549,14 +638,6 @@ bool serve(enum setpoint_type_t sp_type, float x, float y, float z, float vx, fl
|
||||
throw std::runtime_error("No global position");
|
||||
}
|
||||
|
||||
// default frame is local frame
|
||||
if (frame_id.empty())
|
||||
frame_id = local_frame;
|
||||
|
||||
// look up for reference frame
|
||||
auto search = reference_frames.find(frame_id);
|
||||
const string& reference_frame = search == reference_frames.end() ? frame_id : search->second;
|
||||
|
||||
if (sp_type == NAVIGATE || sp_type == NAVIGATE_GLOBAL || sp_type == POSITION || sp_type == VELOCITY || sp_type == ATTITUDE) {
|
||||
// make sure transform from frame_id to reference frame available
|
||||
if (!waitTransform(reference_frame, frame_id, stamp, transform_timeout))
|
||||
@@ -605,12 +686,13 @@ bool serve(enum setpoint_type_t sp_type, float x, float y, float z, float vx, fl
|
||||
|
||||
if (sp_type == POSITION || sp_type == NAVIGATE || sp_type == NAVIGATE_GLOBAL || sp_type == VELOCITY || sp_type == ATTITUDE) {
|
||||
// destination point and/or yaw
|
||||
static PoseStamped ps;
|
||||
PoseStamped ps;
|
||||
ps.header.frame_id = frame_id;
|
||||
ps.header.stamp = stamp;
|
||||
ps.pose.position.x = x;
|
||||
ps.pose.position.y = y;
|
||||
ps.pose.position.z = z;
|
||||
ps.pose.orientation.w = 1.0; // Ensure quaternion is always valid
|
||||
|
||||
if (std::isnan(yaw)) {
|
||||
setpoint_yaw_type = YAW_RATE;
|
||||
@@ -623,7 +705,7 @@ bool serve(enum setpoint_type_t sp_type, float x, float y, float z, float vx, fl
|
||||
} else {
|
||||
setpoint_yaw_type = YAW;
|
||||
setpoint_yaw_rate = 0;
|
||||
ps.pose.orientation = tf::createQuaternionMsgFromRollPitchYaw(roll, pitch, yaw);
|
||||
ps.pose.orientation = tf::createQuaternionMsgFromYaw(yaw);
|
||||
}
|
||||
|
||||
tf_buffer.transform(ps, setpoint_position, reference_frame);
|
||||
@@ -651,6 +733,7 @@ bool serve(enum setpoint_type_t sp_type, float x, float y, float z, float vx, fl
|
||||
|
||||
wait_armed = auto_arm;
|
||||
|
||||
publish_setpoint:
|
||||
publish(stamp); // calculate initial transformed messages first
|
||||
setpoint_timer.start();
|
||||
|
||||
@@ -691,27 +774,27 @@ bool serve(enum setpoint_type_t sp_type, float x, float y, float z, float vx, fl
|
||||
}
|
||||
|
||||
bool navigate(Navigate::Request& req, Navigate::Response& res) {
|
||||
return serve(NAVIGATE, req.x, req.y, req.z, 0, 0, 0, 0, 0, req.yaw, 0, 0, req.yaw_rate, 0, 0, 0, req.speed, req.frame_id, req.auto_arm, res.success, res.message);
|
||||
return serve(NAVIGATE, req.x, req.y, req.z, NAN, NAN, NAN, NAN, NAN, req.yaw, NAN, NAN, req.yaw_rate, NAN, NAN, NAN, req.speed, req.frame_id, req.auto_arm, res.success, res.message);
|
||||
}
|
||||
|
||||
bool navigateGlobal(NavigateGlobal::Request& req, NavigateGlobal::Response& res) {
|
||||
return serve(NAVIGATE_GLOBAL, 0, 0, req.z, 0, 0, 0, 0, 0, req.yaw, 0, 0, req.yaw_rate, req.lat, req.lon, 0, req.speed, req.frame_id, req.auto_arm, res.success, res.message);
|
||||
return serve(NAVIGATE_GLOBAL, NAN, NAN, req.z, NAN, NAN, NAN, NAN, NAN, req.yaw, NAN, NAN, req.yaw_rate, req.lat, req.lon, NAN, req.speed, req.frame_id, req.auto_arm, res.success, res.message);
|
||||
}
|
||||
|
||||
bool setPosition(SetPosition::Request& req, SetPosition::Response& res) {
|
||||
return serve(POSITION, req.x, req.y, req.z, 0, 0, 0, 0, 0, req.yaw, 0, 0, req.yaw_rate, 0, 0, 0, 0, req.frame_id, req.auto_arm, res.success, res.message);
|
||||
return serve(POSITION, req.x, req.y, req.z, NAN, NAN, NAN, NAN, NAN, req.yaw, NAN, NAN, req.yaw_rate, NAN, NAN, NAN, NAN, req.frame_id, req.auto_arm, res.success, res.message);
|
||||
}
|
||||
|
||||
bool setVelocity(SetVelocity::Request& req, SetVelocity::Response& res) {
|
||||
return serve(VELOCITY, 0, 0, 0, req.vx, req.vy, req.vz, 0, 0, req.yaw, 0, 0, req.yaw_rate, 0, 0, 0, 0, req.frame_id, req.auto_arm, res.success, res.message);
|
||||
return serve(VELOCITY, NAN, NAN, NAN, req.vx, req.vy, req.vz, NAN, NAN, req.yaw, NAN, NAN, req.yaw_rate, NAN, NAN, NAN, NAN, req.frame_id, req.auto_arm, res.success, res.message);
|
||||
}
|
||||
|
||||
bool setAttitude(SetAttitude::Request& req, SetAttitude::Response& res) {
|
||||
return serve(ATTITUDE, 0, 0, 0, 0, 0, 0, req.pitch, req.roll, req.yaw, 0, 0, 0, 0, 0, req.thrust, 0, req.frame_id, req.auto_arm, res.success, res.message);
|
||||
return serve(ATTITUDE, NAN, NAN, NAN, NAN, NAN, NAN, req.pitch, req.roll, req.yaw, NAN, NAN, NAN, NAN, NAN, req.thrust, NAN, req.frame_id, req.auto_arm, res.success, res.message);
|
||||
}
|
||||
|
||||
bool setRates(SetRates::Request& req, SetRates::Response& res) {
|
||||
return serve(RATES, 0, 0, 0, 0, 0, 0, 0, 0, 0, req.pitch_rate, req.roll_rate, req.yaw_rate, 0, 0, req.thrust, 0, "", req.auto_arm, res.success, res.message);
|
||||
return serve(RATES, NAN, NAN, NAN, NAN, NAN, NAN, NAN, NAN, NAN, req.pitch_rate, req.roll_rate, req.yaw_rate, NAN, NAN, req.thrust, NAN, "", req.auto_arm, res.success, res.message);
|
||||
}
|
||||
|
||||
bool land(std_srvs::Trigger::Request& req, std_srvs::Trigger::Response& res)
|
||||
@@ -779,6 +862,7 @@ int main(int argc, char **argv)
|
||||
nh_priv.param("auto_release", auto_release, true);
|
||||
nh_priv.param("land_only_in_offboard", land_only_in_offboard, true);
|
||||
nh_priv.param("nav_from_sp", nav_from_sp, true);
|
||||
nh_priv.param("check_kill_switch", check_kill_switch, true);
|
||||
nh_priv.param("default_speed", default_speed, 0.5f);
|
||||
nh_priv.param<string>("body_frame", body.child_frame_id, "body");
|
||||
nh_priv.getParam("reference_frames", reference_frames);
|
||||
@@ -788,6 +872,7 @@ int main(int argc, char **argv)
|
||||
velocity_timeout = ros::Duration(nh_priv.param("velocity_timeout", 2.0));
|
||||
global_position_timeout = ros::Duration(nh_priv.param("global_position_timeout", 10.0));
|
||||
battery_timeout = ros::Duration(nh_priv.param("battery_timeout", 2.0));
|
||||
manual_control_timeout = ros::Duration(nh_priv.param("manual_control_timeout", 0.0));
|
||||
|
||||
transform_timeout = ros::Duration(nh_priv.param("transform_timeout", 0.5));
|
||||
telemetry_transform_timeout = ros::Duration(nh_priv.param("telemetry_transform_timeout", 0.5));
|
||||
@@ -805,6 +890,7 @@ int main(int argc, char **argv)
|
||||
auto global_position_sub = nh.subscribe("mavros/global_position/global", 1, &handleMessage<NavSatFix, global_position>);
|
||||
auto battery_sub = nh.subscribe("mavros/battery", 1, &handleMessage<BatteryState, battery>);
|
||||
auto statustext_sub = nh.subscribe("mavros/statustext/recv", 1, &handleMessage<mavros_msgs::StatusText, statustext>);
|
||||
auto manual_control_sub = nh.subscribe("mavros/manual_control/control", 1, &handleMessage<mavros_msgs::ManualControl, manual_control>);
|
||||
auto local_position_sub = nh.subscribe("mavros/local_position/pose", 1, &handleLocalPosition);
|
||||
|
||||
// Setpoint publishers
|
||||
|
||||
0
clover/www/CATKIN_IGNORE
Normal file
@@ -1,3 +1,5 @@
|
||||
<title>Clover Drone Kit Tools</title>
|
||||
|
||||
<h1>Clover Drone Kit Tools</h1>
|
||||
|
||||
<ul>
|
||||
@@ -6,14 +8,15 @@
|
||||
<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>
|
||||
|
||||
<div class="version"></div>
|
||||
|
||||
<script src="js/roslib.js"></script>
|
||||
<script type="text/javascript">
|
||||
document.querySelector("#wvs").href = location.origin + ':8080';
|
||||
document.querySelector("#butterfly").href = location.origin + ':57575';
|
||||
document.querySelector("#wvs").href = location.protocol + '//' + location.hostname + ':8080';
|
||||
document.querySelector("#butterfly").href = location.protocol + '//' + location.hostname + ':57575';
|
||||
|
||||
// Determine image version
|
||||
var ros = new ROSLIB.Ros({ url: 'ws://' + location.hostname + ':9090' });
|
||||
|
||||
8
clover_blocks/CHANGELOG.rst
Normal file
@@ -0,0 +1,8 @@
|
||||
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||
Changelog for package clover_blocks
|
||||
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||
|
||||
0.21.1 (2020-11-17)
|
||||
-------------------
|
||||
* First release of clover_blocks package to ROS
|
||||
* Contributors: Oleg Kalachev
|
||||
87
clover_blocks/CMakeLists.txt
Normal file
@@ -0,0 +1,87 @@
|
||||
cmake_minimum_required(VERSION 2.8.3)
|
||||
project(clover_blocks)
|
||||
|
||||
find_package(catkin REQUIRED COMPONENTS message_generation)
|
||||
|
||||
add_message_files(
|
||||
FILES
|
||||
Prompt.msg
|
||||
)
|
||||
|
||||
add_service_files(
|
||||
FILES
|
||||
Run.srv
|
||||
Load.srv
|
||||
Store.srv
|
||||
)
|
||||
|
||||
generate_messages(
|
||||
DEPENDENCIES
|
||||
# std_msgs # Or other packages containing msgs
|
||||
)
|
||||
|
||||
catkin_package(
|
||||
# INCLUDE_DIRS include
|
||||
# LIBRARIES roslaunch_editor
|
||||
CATKIN_DEPENDS message_runtime
|
||||
# DEPENDS system_lib
|
||||
)
|
||||
|
||||
#############
|
||||
## Install ##
|
||||
#############
|
||||
|
||||
# all install targets should use catkin DESTINATION variables
|
||||
# See http://ros.org/doc/api/catkin/html/adv_user_guide/variables.html
|
||||
|
||||
## Mark executable scripts (Python etc.) for installation
|
||||
## in contrast to setup.py, you can choose the destination
|
||||
# install(PROGRAMS
|
||||
# scripts/my_python_script
|
||||
# DESTINATION ${CATKIN_PACKAGE_BIN_DESTINATION}
|
||||
# )
|
||||
|
||||
## Mark executables for installation
|
||||
## See http://docs.ros.org/melodic/api/catkin/html/howto/format1/building_executables.html
|
||||
# install(TARGETS ${PROJECT_NAME}_node
|
||||
# RUNTIME DESTINATION ${CATKIN_PACKAGE_BIN_DESTINATION}
|
||||
# )
|
||||
|
||||
## Mark libraries for installation
|
||||
## See http://docs.ros.org/melodic/api/catkin/html/howto/format1/building_libraries.html
|
||||
# install(TARGETS ${PROJECT_NAME}
|
||||
# ARCHIVE DESTINATION ${CATKIN_PACKAGE_LIB_DESTINATION}
|
||||
# LIBRARY DESTINATION ${CATKIN_PACKAGE_LIB_DESTINATION}
|
||||
# RUNTIME DESTINATION ${CATKIN_GLOBAL_BIN_DESTINATION}
|
||||
# )
|
||||
|
||||
## Mark cpp header files for installation
|
||||
# install(DIRECTORY include/${PROJECT_NAME}/
|
||||
# DESTINATION ${CATKIN_PACKAGE_INCLUDE_DESTINATION}
|
||||
# FILES_MATCHING PATTERN "*.h"
|
||||
# PATTERN ".svn" EXCLUDE
|
||||
# )
|
||||
|
||||
## Mark other files for installation (e.g. launch and bag files, etc.)
|
||||
# install(FILES
|
||||
# # myfile1
|
||||
# # myfile2
|
||||
# DESTINATION ${CATKIN_PACKAGE_SHARE_DESTINATION}
|
||||
# )
|
||||
|
||||
catkin_install_python(PROGRAMS src/clover_blocks
|
||||
DESTINATION ${CATKIN_PACKAGE_BIN_DESTINATION}
|
||||
)
|
||||
|
||||
#############
|
||||
## Testing ##
|
||||
#############
|
||||
|
||||
## Add gtest based cpp test target and link libraries
|
||||
# catkin_add_gtest(${PROJECT_NAME}-test test/test_roslaunch_editor.cpp)
|
||||
# if(TARGET ${PROJECT_NAME}-test)
|
||||
# target_link_libraries(${PROJECT_NAME}-test ${PROJECT_NAME})
|
||||
# endif()
|
||||
|
||||
## Add folders to be run by python nosetests
|
||||
# catkin_add_nosetests(test)
|
||||
54
clover_blocks/README.md
Normal file
@@ -0,0 +1,54 @@
|
||||
# clover_blocks
|
||||
|
||||
Blockly programming support for Clover.
|
||||
|
||||
<img src="screenshot.png" width=700>
|
||||
|
||||
See user documentation at the [main Clover documentation site](https://clover.coex.tech/en/blocks.html).
|
||||
|
||||
Internal package documentation is given below.
|
||||
|
||||
## Frontend
|
||||
|
||||
The frontend files are located in [`www`](./www/) subdirectory. The frontend application uses [`roblib.js`](http://wiki.ros.org/roslibjs) library for communicating with backend node and other ROS resources.
|
||||
|
||||
## `clover_blocks` node
|
||||
|
||||
`clover_blocks` is the blocks programming backend, implementing all the services and topics needed for running Blockly-generated Python script.
|
||||
|
||||
### Services
|
||||
|
||||
* `~run` ([*clover_blocks/Run*](srv/Run.srv)) – run Blockly-generated program (in Python).
|
||||
* `~stop` ([*std_srvs/Trigger*](http://docs.ros.org/melodic/api/std_srvs/html/srv/Trigger.html)) – terminate the running program.
|
||||
* `~store` ([*clover_blocks/load*](srv/Store.srv)) – store a user program (to `<package_path>/programs` by default).
|
||||
* `~load` ([*clover_blocks/load*](srv/Load.srv)) – load all the stored programs.
|
||||
|
||||
### Parameters
|
||||
|
||||
* `~programs_dir` (*string*) – directory for user programs.
|
||||
|
||||
Parameters read by frontend:
|
||||
|
||||
* `~navigate_tolerance` (*float*) – distance tolerance in meters, used for navigate-like blocks (default: 0.2).
|
||||
* `~yaw_tolerance` (*float*) – yaw angle tolerance in degrees, used in set_yaw block (default: 20).
|
||||
* `~sleep_time` (*float*) – duration of sleep in loop cycles, used for navigate-like blocks (default: 0.2).
|
||||
* `~confirm_run` (*bool*) – enable confirmation to run the program (default: true).
|
||||
|
||||
These parameters also can be set as URL GET-parameters, for example:
|
||||
|
||||
```
|
||||
http://<hostname>/clover_blocks/?navigate_tolerance=0.5&sleep_time=0.1
|
||||
```
|
||||
|
||||
### Topics
|
||||
|
||||
#### Published
|
||||
|
||||
* `~running` ([*std_msgs/Bool*](http://docs.ros.org/melodic/api/std_msgs/html/msg/Bool.html)) – indicates if the program is currently running.
|
||||
* `~block` ([*std_msgs/String*](http://docs.ros.org/melodic/api/std_msgs/html/msg/String.html)) – current executing block (maximum topic rate is limited).
|
||||
* `~error` ([*std_msgs/String*](http://docs.ros.org/melodic/api/std_msgs/html/msg/String.html)) – user program errors and exceptions.
|
||||
* `~prompt` ([*clover_blocks/Prompt*](msg/Prompt.msg)) – user input request (includes random request ID string).
|
||||
|
||||
This topic is published from the frontend side:
|
||||
|
||||
* `~prompt/<request_id>` ([*std_msgs/String*](http://docs.ros.org/melodic/api/std_msgs/html/msg/String.html)) – user input response.
|
||||
2
clover_blocks/msg/Prompt.msg
Normal file
@@ -0,0 +1,2 @@
|
||||
string message # message for prompt
|
||||
string id # user response should be published to ~input/<id> topic
|
||||
48
clover_blocks/package.xml
Normal file
@@ -0,0 +1,48 @@
|
||||
<?xml version="1.0"?>
|
||||
<package format="2">
|
||||
<name>clover_blocks</name>
|
||||
<version>0.21.1</version>
|
||||
<description>Blockly programming support for Clover</description>
|
||||
<maintainer email="okalachev@gmail.com">Oleg Kalachev</maintainer>
|
||||
<license>MIT</license>
|
||||
|
||||
<!-- Url tags are optional, but multiple are allowed, one per tag -->
|
||||
<!-- Optional attribute type can be: website, bugtracker, or repository -->
|
||||
<url type="repository">https://github.com/CopterExpress/clover</url>
|
||||
|
||||
<!-- Author tags are optional, multiple are allowed, one per tag -->
|
||||
<!-- Authors do not have to be maintainers, but could be -->
|
||||
<author email="okalachev@gmail.com">Oleg Kalachev</author>
|
||||
|
||||
<!-- The *depend tags are used to specify dependencies -->
|
||||
<!-- Dependencies can be catkin packages or system dependencies -->
|
||||
<!-- Examples: -->
|
||||
<!-- Use depend as a shortcut for packages that are both build and exec dependencies -->
|
||||
<!-- <depend>roscpp</depend> -->
|
||||
<!-- Note that this is equivalent to the following: -->
|
||||
<!-- <build_depend>roscpp</build_depend> -->
|
||||
<!-- <exec_depend>roscpp</exec_depend> -->
|
||||
<!-- Use build_depend for packages you need at compile time: -->
|
||||
<!-- <build_depend>message_generation</build_depend> -->
|
||||
<!-- Use build_export_depend for packages you need in order to build against this package: -->
|
||||
<!-- <build_export_depend>message_generation</build_export_depend> -->
|
||||
<!-- Use buildtool_depend for build tool packages: -->
|
||||
<!-- <buildtool_depend>catkin</buildtool_depend> -->
|
||||
<!-- Use exec_depend for packages you need at runtime: -->
|
||||
<!-- <exec_depend>message_runtime</exec_depend> -->
|
||||
<!-- Use test_depend for packages you need only for testing: -->
|
||||
<!-- <test_depend>gtest</test_depend> -->
|
||||
<!-- Use doc_depend for packages you need only for building documentation: -->
|
||||
<!-- <doc_depend>doxygen</doc_depend> -->
|
||||
<buildtool_depend>catkin</buildtool_depend>
|
||||
|
||||
<depend>message_generation</depend>
|
||||
<depend>message_runtime</depend>
|
||||
<depend>rospy</depend>
|
||||
|
||||
<!-- The export tag contains other, unspecified, tags -->
|
||||
<export>
|
||||
<!-- Other tools can request additional information be placed here -->
|
||||
|
||||
</export>
|
||||
</package>
|
||||
73
clover_blocks/programs/examples/aruco-map.xml
Normal file
@@ -0,0 +1,73 @@
|
||||
<xml xmlns="https://developers.google.com/blockly/xml">
|
||||
<block type="take_off" id="w4,Hi[}0b.mX68K|hOJv" x="38" y="63">
|
||||
<field name="WAIT">TRUE</field>
|
||||
<value name="ALT">
|
||||
<shadow type="math_number" id="q!Ln!d`jutn*3Gy56B0A">
|
||||
<field name="NUM">1.5</field>
|
||||
</shadow>
|
||||
</value>
|
||||
<next>
|
||||
<block type="controls_repeat_ext" id="fD/HWb]kb!^pYK{UkM;0">
|
||||
<value name="TIMES">
|
||||
<shadow type="math_number" id="%FP0k|kaf~A`0N;M{Oiy">
|
||||
<field name="NUM">10</field>
|
||||
</shadow>
|
||||
</value>
|
||||
<statement name="DO">
|
||||
<block type="navigate" id="qM5ROiq4r:$lq}8U_wol">
|
||||
<field name="FRAME_ID">ARUCO_MAP</field>
|
||||
<field name="WAIT">TRUE</field>
|
||||
<value name="X">
|
||||
<shadow type="math_number" id="=MBV;9zGH8S`Xh57/E;C">
|
||||
<field name="NUM">0</field>
|
||||
</shadow>
|
||||
<block type="text_prompt_ext" id="rUDMP2~yFR!7E`Q]pR/i">
|
||||
<mutation type="NUMBER"></mutation>
|
||||
<field name="TYPE">NUMBER</field>
|
||||
<value name="TEXT">
|
||||
<shadow type="text" id="z+Q3vS?)kxHl?HTcuI?(">
|
||||
<field name="TEXT">Enter X</field>
|
||||
</shadow>
|
||||
</value>
|
||||
</block>
|
||||
</value>
|
||||
<value name="Y">
|
||||
<shadow type="math_number" id="%$`av8A.w}vNqG-]1GOn">
|
||||
<field name="NUM">0</field>
|
||||
</shadow>
|
||||
<block type="text_prompt_ext" id=".AjhH^Rh*i}+14s)K-:g">
|
||||
<mutation type="NUMBER"></mutation>
|
||||
<field name="TYPE">NUMBER</field>
|
||||
<value name="TEXT">
|
||||
<shadow type="text" id="x#)(kg5PB;0uZA5;{(GT">
|
||||
<field name="TEXT">Enter Y</field>
|
||||
</shadow>
|
||||
</value>
|
||||
</block>
|
||||
</value>
|
||||
<value name="Z">
|
||||
<shadow type="math_number" id="T,]q+-@V;tCYLy$-(o3}">
|
||||
<field name="NUM">1.5</field>
|
||||
</shadow>
|
||||
</value>
|
||||
<value name="ID">
|
||||
<shadow type="math_number" id="VRo?s#0d)Gl@9fsK@gR=">
|
||||
<field name="NUM">0</field>
|
||||
</shadow>
|
||||
</value>
|
||||
<value name="SPEED">
|
||||
<shadow type="math_number" id="mmZc+d=W})w.AN*B_dSe">
|
||||
<field name="NUM">0.5</field>
|
||||
</shadow>
|
||||
</value>
|
||||
</block>
|
||||
</statement>
|
||||
<next>
|
||||
<block type="land" id="JB%yj/X~K=8A2=Q*7cRs">
|
||||
<field name="WAIT">TRUE</field>
|
||||
</block>
|
||||
</next>
|
||||
</block>
|
||||
</next>
|
||||
</block>
|
||||
</xml>
|
||||
64
clover_blocks/programs/examples/aruco-marker.xml
Normal file
@@ -0,0 +1,64 @@
|
||||
<xml xmlns="https://developers.google.com/blockly/xml">
|
||||
<block type="take_off" id="R@=3~Fq;AxFaRO{ZDFUM" x="37" y="63">
|
||||
<field name="WAIT">TRUE</field>
|
||||
<value name="ALT">
|
||||
<shadow type="math_number" id="cf8/,N48N;Fvn@EWB%,B">
|
||||
<field name="NUM">1.5</field>
|
||||
</shadow>
|
||||
</value>
|
||||
<next>
|
||||
<block type="controls_repeat_ext" id="qc$F96[A^%lj,-l[fhX+">
|
||||
<value name="TIMES">
|
||||
<shadow type="math_number" id="v0QgNIpGzMIb`P@8D@}.">
|
||||
<field name="NUM">3</field>
|
||||
</shadow>
|
||||
</value>
|
||||
<statement name="DO">
|
||||
<block type="navigate" id="]kCOMt@NSf$9:N1Fx~dE">
|
||||
<field name="FRAME_ID">ARUCO</field>
|
||||
<field name="WAIT">TRUE</field>
|
||||
<value name="X">
|
||||
<shadow type="math_number" id="}(7P5,{6%^::Gzb;kRaf">
|
||||
<field name="NUM">0</field>
|
||||
</shadow>
|
||||
</value>
|
||||
<value name="Y">
|
||||
<shadow type="math_number" id="hz#sFvY/;IL5IRLQVa.K">
|
||||
<field name="NUM">0</field>
|
||||
</shadow>
|
||||
</value>
|
||||
<value name="Z">
|
||||
<shadow type="math_number" id="n0ULZn64%k.:,l(,D?TZ">
|
||||
<field name="NUM">1</field>
|
||||
</shadow>
|
||||
</value>
|
||||
<value name="ID">
|
||||
<shadow type="math_number" id="P4^twyJo6as#G1}^Dlq8">
|
||||
<field name="NUM">0</field>
|
||||
</shadow>
|
||||
<block type="text_prompt_ext" id="ot;{twL$8`H*Wiafz3D,">
|
||||
<mutation type="NUMBER"></mutation>
|
||||
<field name="TYPE">NUMBER</field>
|
||||
<value name="TEXT">
|
||||
<shadow type="text" id="@P[TyPj[n1*;EcUC?lwF">
|
||||
<field name="TEXT">Enter marker ID</field>
|
||||
</shadow>
|
||||
</value>
|
||||
</block>
|
||||
</value>
|
||||
<value name="SPEED">
|
||||
<shadow type="math_number" id="WrsUXacZ2w)D]d?:@ec_">
|
||||
<field name="NUM">0.5</field>
|
||||
</shadow>
|
||||
</value>
|
||||
</block>
|
||||
</statement>
|
||||
<next>
|
||||
<block type="land" id="G5+Fs.6Y4(K9Dw`wjgua">
|
||||
<field name="WAIT">TRUE</field>
|
||||
</block>
|
||||
</next>
|
||||
</block>
|
||||
</next>
|
||||
</block>
|
||||
</xml>
|
||||
97
clover_blocks/programs/examples/flight-led.xml
Normal file
@@ -0,0 +1,97 @@
|
||||
<xml xmlns="https://developers.google.com/blockly/xml">
|
||||
<block type="take_off" id="R@=3~Fq;AxFaRO{ZDFUM" x="162" y="63">
|
||||
<field name="WAIT">TRUE</field>
|
||||
<value name="ALT">
|
||||
<shadow type="math_number" id="cf8/,N48N;Fvn@EWB%,B">
|
||||
<field name="NUM">1</field>
|
||||
</shadow>
|
||||
</value>
|
||||
<next>
|
||||
<block type="set_effect" id="5K8qDD0/@Ab!k+ad6IPj">
|
||||
<field name="EFFECT">FILL</field>
|
||||
<value name="COLOR">
|
||||
<shadow type="colour_picker" id="=*Y*L:1DI7y$.RR$6jNQ">
|
||||
<field name="COLOUR">#ff0000</field>
|
||||
</shadow>
|
||||
</value>
|
||||
<next>
|
||||
<block type="navigate" id="kE7TL3+{PI.GiXby~SyO">
|
||||
<field name="FRAME_ID">BODY</field>
|
||||
<field name="WAIT">TRUE</field>
|
||||
<value name="X">
|
||||
<shadow type="math_number" id="W$eQ*Xv/e(*`e%8--W:P">
|
||||
<field name="NUM">1</field>
|
||||
</shadow>
|
||||
</value>
|
||||
<value name="Y">
|
||||
<shadow type="math_number" id="i~r{%5mpU|}FL|9p!5yG">
|
||||
<field name="NUM">0</field>
|
||||
</shadow>
|
||||
</value>
|
||||
<value name="Z">
|
||||
<shadow type="math_number" id="fZ{Cz~^LoWvM#,#;!co_">
|
||||
<field name="NUM">0</field>
|
||||
</shadow>
|
||||
</value>
|
||||
<value name="ID">
|
||||
<shadow type="math_number" id="z$Hj|-?4e3zy@Jx$/THh">
|
||||
<field name="NUM">0</field>
|
||||
</shadow>
|
||||
</value>
|
||||
<value name="SPEED">
|
||||
<shadow type="math_number" id="FjRM:aex=:/l_``^zcO]">
|
||||
<field name="NUM">0.5</field>
|
||||
</shadow>
|
||||
</value>
|
||||
<next>
|
||||
<block type="set_effect" id="Q^DQoW/6G$7#YPlXc}%]">
|
||||
<field name="EFFECT">FILL</field>
|
||||
<value name="COLOR">
|
||||
<shadow type="colour_picker" id="mjOY6]=uMY4$r8^n:n|}">
|
||||
<field name="COLOUR">#3333ff</field>
|
||||
</shadow>
|
||||
</value>
|
||||
<next>
|
||||
<block type="navigate" id=";|j@sXR{9)9@ran7g[;~">
|
||||
<field name="FRAME_ID">BODY</field>
|
||||
<field name="WAIT">TRUE</field>
|
||||
<value name="X">
|
||||
<shadow type="math_number" id="TH(htYn}*/a{[::sFQ[x">
|
||||
<field name="NUM">-1</field>
|
||||
</shadow>
|
||||
</value>
|
||||
<value name="Y">
|
||||
<shadow type="math_number" id="h@`=v?y+Tuh,I)wv?+`f">
|
||||
<field name="NUM">0</field>
|
||||
</shadow>
|
||||
</value>
|
||||
<value name="Z">
|
||||
<shadow type="math_number" id="pzz:U%?m/~~B$-FF!fD?">
|
||||
<field name="NUM">0</field>
|
||||
</shadow>
|
||||
</value>
|
||||
<value name="ID">
|
||||
<shadow type="math_number" id="Ze2Nun;[K{X.1kE0anMF">
|
||||
<field name="NUM">0</field>
|
||||
</shadow>
|
||||
</value>
|
||||
<value name="SPEED">
|
||||
<shadow type="math_number" id="+[A5TSXF:hw4T1M]e~Wu">
|
||||
<field name="NUM">0.5</field>
|
||||
</shadow>
|
||||
</value>
|
||||
<next>
|
||||
<block type="land" id="G5+Fs.6Y4(K9Dw`wjgua">
|
||||
<field name="WAIT">TRUE</field>
|
||||
</block>
|
||||
</next>
|
||||
</block>
|
||||
</next>
|
||||
</block>
|
||||
</next>
|
||||
</block>
|
||||
</next>
|
||||
</block>
|
||||
</next>
|
||||
</block>
|
||||
</xml>
|
||||
308
clover_blocks/programs/examples/flip.xml
Normal file
@@ -0,0 +1,308 @@
|
||||
<xml xmlns="https://developers.google.com/blockly/xml">
|
||||
<variables>
|
||||
<variable id="MEu_bi$Xk5e(#Q`Yu=k0">start_x</variable>
|
||||
<variable id="GtS.)8^|(~RL*T4.~#VV">start_y</variable>
|
||||
<variable id="jksdQ,]0F47Xan8{_(?+">start_z</variable>
|
||||
</variables>
|
||||
<block type="procedures_defnoreturn" id="Uo{/lI4(1i[O|U^jyh]y" x="188" y="62">
|
||||
<field name="NAME">flip</field>
|
||||
<comment pinned="false" h="80" w="160">Describe this function...</comment>
|
||||
<statement name="STACK">
|
||||
<block type="procedures_callnoreturn" id="G7`l2OBCg~ISh(XsrkRv">
|
||||
<mutation name="memorize position"></mutation>
|
||||
<next>
|
||||
<block type="setpoint" id="8%(,J3=!CEUALDr5gFT+">
|
||||
<field name="TYPE">RATES</field>
|
||||
<field name="FRAME_ID">BODY</field>
|
||||
<comment pinned="false" h="80" w="160">bump up</comment>
|
||||
<value name="VX">
|
||||
<shadow type="math_number" id="!@rHW+cG*U6.Py:.;qc)">
|
||||
<field name="NUM">0</field>
|
||||
</shadow>
|
||||
</value>
|
||||
<value name="VY">
|
||||
<shadow type="math_number" id="n#I~l7$%1m^@Oz+w;k[H">
|
||||
<field name="NUM">0</field>
|
||||
</shadow>
|
||||
</value>
|
||||
<value name="VZ">
|
||||
<shadow type="math_number" id="l0EphD#!^4jX#%UA-rxX">
|
||||
<field name="NUM">0</field>
|
||||
</shadow>
|
||||
</value>
|
||||
<value name="PITCH">
|
||||
<shadow type="math_number" id="Ad.[@07QtZcb;(:^,Kjg">
|
||||
<field name="NUM">0</field>
|
||||
</shadow>
|
||||
</value>
|
||||
<value name="ROLL">
|
||||
<shadow type="math_number" id="50,,4i.p6KR:e3/l|k2i">
|
||||
<field name="NUM">0</field>
|
||||
</shadow>
|
||||
</value>
|
||||
<value name="YAW">
|
||||
<shadow type="math_number" id="(:O}={3*LZ#KDiC@;b[F">
|
||||
<field name="NUM">0</field>
|
||||
</shadow>
|
||||
</value>
|
||||
<value name="THRUST">
|
||||
<shadow type="math_number" id="EC6yU;oHb#y-8?W`B/JC">
|
||||
<field name="NUM">1</field>
|
||||
</shadow>
|
||||
</value>
|
||||
<value name="ID">
|
||||
<shadow type="math_number" id="k.X^bynEZH2dyG1=Y6lr">
|
||||
<field name="NUM">0</field>
|
||||
</shadow>
|
||||
</value>
|
||||
<next>
|
||||
<block type="wait" id="#ga)cR4TsF[9t?;zc1H~">
|
||||
<value name="TIME">
|
||||
<shadow type="math_number" id="zg5fX7[;O,lQt*Txg|tn">
|
||||
<field name="NUM">0.2</field>
|
||||
</shadow>
|
||||
</value>
|
||||
<next>
|
||||
<block type="setpoint" id="j,yf}/lrx*2J}X%^5LG{">
|
||||
<field name="TYPE">RATES</field>
|
||||
<field name="FRAME_ID">BODY</field>
|
||||
<comment pinned="false" h="80" w="160">maximum pitch rate</comment>
|
||||
<value name="VX">
|
||||
<shadow type="math_number" id="^WF12EBPyIXhZdpsj;=D">
|
||||
<field name="NUM">0</field>
|
||||
</shadow>
|
||||
</value>
|
||||
<value name="VY">
|
||||
<shadow type="math_number" id="C/uBsz]ObzwyHxGqzUP_">
|
||||
<field name="NUM">0</field>
|
||||
</shadow>
|
||||
</value>
|
||||
<value name="VZ">
|
||||
<shadow type="math_number" id="4?)O3G/j`UuVTMImLq{T">
|
||||
<field name="NUM">0</field>
|
||||
</shadow>
|
||||
</value>
|
||||
<value name="PITCH">
|
||||
<shadow type="math_number" id="sdCVFTmVkc0v2|*3Fy~h">
|
||||
<field name="NUM">30</field>
|
||||
</shadow>
|
||||
</value>
|
||||
<value name="ROLL">
|
||||
<shadow type="math_number" id="V1o!AV[`!OnhrUP4~$=!">
|
||||
<field name="NUM">0</field>
|
||||
</shadow>
|
||||
</value>
|
||||
<value name="YAW">
|
||||
<shadow type="math_number" id="0e;`*B;ghV*%=ETSvzSM">
|
||||
<field name="NUM">0</field>
|
||||
</shadow>
|
||||
</value>
|
||||
<value name="THRUST">
|
||||
<shadow type="math_number" id="K@VAeOH2bEwc#@7_M!@l">
|
||||
<field name="NUM">0.2</field>
|
||||
</shadow>
|
||||
</value>
|
||||
<value name="ID">
|
||||
<shadow type="math_number" id="c6ycgS!D}bIK8pl8oAv+">
|
||||
<field name="NUM">0</field>
|
||||
</shadow>
|
||||
</value>
|
||||
<next>
|
||||
<block type="controls_whileUntil" id="H_6do.wf6H.E$?5;$uw8">
|
||||
<field name="MODE">WHILE</field>
|
||||
<value name="BOOL">
|
||||
<block type="logic_boolean" id="pu%GH9}wZvUV{RnGk6Se">
|
||||
<field name="BOOL">TRUE</field>
|
||||
</block>
|
||||
</value>
|
||||
<statement name="DO">
|
||||
<block type="controls_if" id="l0w?CSzU]S(K9eL-1(1r">
|
||||
<value name="IF0">
|
||||
<block type="logic_operation" id="gtXXJ7OFs=1BynL@|R{.">
|
||||
<field name="OP">OR</field>
|
||||
<value name="A">
|
||||
<block type="logic_compare" id="2%9ns$Jk(8M[8$~9o(=*">
|
||||
<field name="OP">GT</field>
|
||||
<value name="A">
|
||||
<block type="math_single" id="#gr7h89vpJyc8bnbWU9O">
|
||||
<field name="OP">ABS</field>
|
||||
<value name="NUM">
|
||||
<shadow type="math_number" id="5paq?]87z}}+@~NALY}.">
|
||||
<field name="NUM">9</field>
|
||||
</shadow>
|
||||
<block type="get_attitude" id="awk0-~@[jWFVQ+ZPi=Dc">
|
||||
<field name="FIELD">PITCH</field>
|
||||
</block>
|
||||
</value>
|
||||
</block>
|
||||
</value>
|
||||
<value name="B">
|
||||
<block type="math_number" id=",4p]fd#kwxy`DtCMtraW">
|
||||
<field name="NUM">90</field>
|
||||
</block>
|
||||
</value>
|
||||
</block>
|
||||
</value>
|
||||
<value name="B">
|
||||
<block type="logic_compare" id="?TPG3^?eg4l~CKM,3DfO">
|
||||
<field name="OP">GT</field>
|
||||
<value name="A">
|
||||
<block type="math_single" id="yS*/-+E3TMpZ]%`1j*Up">
|
||||
<field name="OP">ABS</field>
|
||||
<value name="NUM">
|
||||
<shadow type="math_number">
|
||||
<field name="NUM">9</field>
|
||||
</shadow>
|
||||
<block type="get_attitude" id="~E3RS!on]G(?IZ?SVA#J">
|
||||
<field name="FIELD">ROLL</field>
|
||||
</block>
|
||||
</value>
|
||||
</block>
|
||||
</value>
|
||||
<value name="B">
|
||||
<block type="math_number" id="#y??I}u#OmOTK:`!pkNS">
|
||||
<field name="NUM">90</field>
|
||||
</block>
|
||||
</value>
|
||||
</block>
|
||||
</value>
|
||||
</block>
|
||||
</value>
|
||||
<statement name="DO0">
|
||||
<block type="controls_flow_statements" id="X|V=r3BDKw9fv)u5EY3.">
|
||||
<field name="FLOW">BREAK</field>
|
||||
</block>
|
||||
</statement>
|
||||
</block>
|
||||
</statement>
|
||||
<next>
|
||||
<block type="procedures_callnoreturn" id="?;sq{#xJ+]bD`yJ#(]o1">
|
||||
<mutation name="navigate to memorized position"></mutation>
|
||||
</block>
|
||||
</next>
|
||||
</block>
|
||||
</next>
|
||||
</block>
|
||||
</next>
|
||||
</block>
|
||||
</next>
|
||||
</block>
|
||||
</next>
|
||||
</block>
|
||||
</statement>
|
||||
</block>
|
||||
<block type="procedures_defnoreturn" id="!Tv!F*.A}=]dW=C6X@-`" x="538" y="62">
|
||||
<field name="NAME">memorize position</field>
|
||||
<comment pinned="false" h="80" w="160">Describe this function...</comment>
|
||||
<statement name="STACK">
|
||||
<block type="variables_set" id="s,o|q7_A/fSV+c0E)b^k">
|
||||
<field name="VAR" id="MEu_bi$Xk5e(#Q`Yu=k0">start_x</field>
|
||||
<value name="VALUE">
|
||||
<block type="get_position" id="f#,.s%hV^19JJ;G/DO):">
|
||||
<field name="FIELD">X</field>
|
||||
<field name="FRAME_ID">MAP</field>
|
||||
<value name="ID">
|
||||
<shadow type="math_number" id="rJRRE#;#JFg}gY+34LVi">
|
||||
<field name="NUM">0</field>
|
||||
</shadow>
|
||||
</value>
|
||||
</block>
|
||||
</value>
|
||||
<next>
|
||||
<block type="variables_set" id="E+2Pfn3JOB{r=DQ3f1b`">
|
||||
<field name="VAR" id="GtS.)8^|(~RL*T4.~#VV">start_y</field>
|
||||
<value name="VALUE">
|
||||
<block type="get_position" id="J#y+_prX(DI;j8gFO81H">
|
||||
<field name="FIELD">Y</field>
|
||||
<field name="FRAME_ID">MAP</field>
|
||||
<value name="ID">
|
||||
<shadow type="math_number" id="_bnV`SCa:|Vl#sRlYA@}">
|
||||
<field name="NUM">0</field>
|
||||
</shadow>
|
||||
</value>
|
||||
</block>
|
||||
</value>
|
||||
<next>
|
||||
<block type="variables_set" id="t*TI?p-h#qC_kC)jM8q0">
|
||||
<field name="VAR" id="jksdQ,]0F47Xan8{_(?+">start_z</field>
|
||||
<value name="VALUE">
|
||||
<block type="get_position" id="Xh#8yLEMxT|bQ}jYvk6/">
|
||||
<field name="FIELD">Z</field>
|
||||
<field name="FRAME_ID">MAP</field>
|
||||
<value name="ID">
|
||||
<shadow type="math_number" id="z3FTv/jt^H7dVYx1`$$C">
|
||||
<field name="NUM">0</field>
|
||||
</shadow>
|
||||
</value>
|
||||
</block>
|
||||
</value>
|
||||
</block>
|
||||
</next>
|
||||
</block>
|
||||
</next>
|
||||
</block>
|
||||
</statement>
|
||||
</block>
|
||||
<block type="procedures_defnoreturn" id="$p3=p^fBz}k5Pg1]svL," x="563" y="213">
|
||||
<field name="NAME">navigate to memorized position</field>
|
||||
<comment pinned="false" h="80" w="160">Describe this function...</comment>
|
||||
<statement name="STACK">
|
||||
<block type="navigate" id="#7b*(J_t9t)V,Arb)3;R">
|
||||
<field name="FRAME_ID">MAP</field>
|
||||
<field name="WAIT">TRUE</field>
|
||||
<value name="X">
|
||||
<shadow type="math_number">
|
||||
<field name="NUM">0</field>
|
||||
</shadow>
|
||||
<block type="variables_get" id="X#O!NcMac+a9WKL;l7?W">
|
||||
<field name="VAR" id="MEu_bi$Xk5e(#Q`Yu=k0">start_x</field>
|
||||
</block>
|
||||
</value>
|
||||
<value name="Y">
|
||||
<shadow type="math_number">
|
||||
<field name="NUM">0</field>
|
||||
</shadow>
|
||||
<block type="variables_get" id="C(=1.r0+01|e3+3qs%SD">
|
||||
<field name="VAR" id="GtS.)8^|(~RL*T4.~#VV">start_y</field>
|
||||
</block>
|
||||
</value>
|
||||
<value name="Z">
|
||||
<shadow type="math_number">
|
||||
<field name="NUM">0</field>
|
||||
</shadow>
|
||||
<block type="variables_get" id="?v;YVETEO%vUqgmiro^/">
|
||||
<field name="VAR" id="jksdQ,]0F47Xan8{_(?+">start_z</field>
|
||||
</block>
|
||||
</value>
|
||||
<value name="ID">
|
||||
<shadow type="math_number" id="ALt.9P$^_]upK}Q9_M,5">
|
||||
<field name="NUM">0</field>
|
||||
</shadow>
|
||||
</value>
|
||||
<value name="SPEED">
|
||||
<shadow type="math_number" id="ObO|OuF^d,1|Bx{Y`O-R">
|
||||
<field name="NUM">5</field>
|
||||
</shadow>
|
||||
</value>
|
||||
</block>
|
||||
</statement>
|
||||
</block>
|
||||
<block type="take_off" id="I1oP(b3wChmK?WgPtULz" x="563" y="612">
|
||||
<field name="WAIT">TRUE</field>
|
||||
<value name="ALT">
|
||||
<shadow type="math_number" id="N1EX*JgURuG783yO+B^X">
|
||||
<field name="NUM">2</field>
|
||||
</shadow>
|
||||
</value>
|
||||
<next>
|
||||
<block type="procedures_callnoreturn" id="(Dc3I{36Kt@1KHN7Ef.m">
|
||||
<mutation name="flip"></mutation>
|
||||
<next>
|
||||
<block type="land" id=";c+lM(v6`13$VK`~jZ|5">
|
||||
<field name="WAIT">TRUE</field>
|
||||
</block>
|
||||
</next>
|
||||
</block>
|
||||
</next>
|
||||
</block>
|
||||
</xml>
|
||||
184
clover_blocks/programs/examples/functions.xml
Normal file
@@ -0,0 +1,184 @@
|
||||
<xml xmlns="https://developers.google.com/blockly/xml">
|
||||
<variables>
|
||||
<variable id="MEu_bi$Xk5e(#Q`Yu=k0">start_x</variable>
|
||||
<variable id="GtS.)8^|(~RL*T4.~#VV">start_y</variable>
|
||||
<variable id="jksdQ,]0F47Xan8{_(?+">start_z</variable>
|
||||
</variables>
|
||||
<block type="procedures_defnoreturn" id="X0i)DAnNpakX]gr;CC0}" x="588" y="88">
|
||||
<field name="NAME">memorize position</field>
|
||||
<comment pinned="false" h="80" w="160">Describe this function...</comment>
|
||||
<statement name="STACK">
|
||||
<block type="variables_set" id="Ma4s0pE-i`P:(-|?c88v">
|
||||
<field name="VAR" id="MEu_bi$Xk5e(#Q`Yu=k0">start_x</field>
|
||||
<value name="VALUE">
|
||||
<block type="get_position" id="~uz[sPf[(s,15#x]3tAw">
|
||||
<field name="FIELD">X</field>
|
||||
<field name="FRAME_ID">MAP</field>
|
||||
<value name="ID">
|
||||
<shadow type="math_number" id="V#rB*5s3W^*q75}gScM(">
|
||||
<field name="NUM">0</field>
|
||||
</shadow>
|
||||
</value>
|
||||
</block>
|
||||
</value>
|
||||
<next>
|
||||
<block type="variables_set" id="I07,0;W#gn1CNY697O9n">
|
||||
<field name="VAR" id="GtS.)8^|(~RL*T4.~#VV">start_y</field>
|
||||
<value name="VALUE">
|
||||
<block type="get_position" id="z(5A+nNX@tWO[J/X6Hb(">
|
||||
<field name="FIELD">Y</field>
|
||||
<field name="FRAME_ID">MAP</field>
|
||||
<value name="ID">
|
||||
<shadow type="math_number" id="6dM^zy88YqX`3ch{IH{1">
|
||||
<field name="NUM">0</field>
|
||||
</shadow>
|
||||
</value>
|
||||
</block>
|
||||
</value>
|
||||
<next>
|
||||
<block type="variables_set" id="AGgAbxz?+u_2^h;Xo4oc">
|
||||
<field name="VAR" id="jksdQ,]0F47Xan8{_(?+">start_z</field>
|
||||
<value name="VALUE">
|
||||
<block type="get_position" id="k~cMq+jvE^,Ip*kKUmw]">
|
||||
<field name="FIELD">Z</field>
|
||||
<field name="FRAME_ID">MAP</field>
|
||||
<value name="ID">
|
||||
<shadow type="math_number" id="Q8RU-5,2UG*IfCeZg0cy">
|
||||
<field name="NUM">0</field>
|
||||
</shadow>
|
||||
</value>
|
||||
</block>
|
||||
</value>
|
||||
</block>
|
||||
</next>
|
||||
</block>
|
||||
</next>
|
||||
</block>
|
||||
</statement>
|
||||
</block>
|
||||
<block type="take_off" id=".0#}q|m$C-GD,.fM/9:/" x="137" y="162">
|
||||
<field name="WAIT">TRUE</field>
|
||||
<value name="ALT">
|
||||
<shadow type="math_number" id="H6G+npH8DS90OnBKP;qy">
|
||||
<field name="NUM">2</field>
|
||||
</shadow>
|
||||
</value>
|
||||
<next>
|
||||
<block type="procedures_callnoreturn" id="_r_hGwEy6uksz}DtrwxW">
|
||||
<mutation name="memorize position"></mutation>
|
||||
<next>
|
||||
<block type="navigate" id="e{_?bCxQ}za#e~~A2GmJ">
|
||||
<field name="FRAME_ID">ARUCO_MAP</field>
|
||||
<field name="WAIT">TRUE</field>
|
||||
<value name="X">
|
||||
<shadow type="math_number" id="}P]lFX9(He:*{Rvp8[.q">
|
||||
<field name="NUM">0</field>
|
||||
</shadow>
|
||||
<block type="text_prompt_ext" id="L:~.WP`isNJ/TBBP75.{">
|
||||
<mutation type="NUMBER"></mutation>
|
||||
<field name="TYPE">NUMBER</field>
|
||||
<value name="TEXT">
|
||||
<shadow type="text" id="v87(;,:4$T8wgbByRv`z">
|
||||
<field name="TEXT">Input X</field>
|
||||
</shadow>
|
||||
</value>
|
||||
</block>
|
||||
</value>
|
||||
<value name="Y">
|
||||
<shadow type="math_number" id="eMbKtnF{B^P*p7zRD8SX">
|
||||
<field name="NUM">0</field>
|
||||
</shadow>
|
||||
<block type="text_prompt_ext" id="fp[sLcO^N:q}9k6zYwnN">
|
||||
<mutation type="NUMBER"></mutation>
|
||||
<field name="TYPE">NUMBER</field>
|
||||
<value name="TEXT">
|
||||
<shadow type="text" id="2Bqk0Rm@h*Vef,,:0c!+">
|
||||
<field name="TEXT">Input Y</field>
|
||||
</shadow>
|
||||
</value>
|
||||
</block>
|
||||
</value>
|
||||
<value name="Z">
|
||||
<shadow type="math_number" id="1sLNKuRa}07Ek(eHK;/S">
|
||||
<field name="NUM">2</field>
|
||||
</shadow>
|
||||
</value>
|
||||
<value name="ID">
|
||||
<shadow type="math_number" id="guM,}nHUz^a?_H3(b{FW">
|
||||
<field name="NUM">0</field>
|
||||
</shadow>
|
||||
</value>
|
||||
<value name="SPEED">
|
||||
<shadow type="math_number" id=".EckPx#fD.[:qSk}5/-J">
|
||||
<field name="NUM">0.5</field>
|
||||
</shadow>
|
||||
</value>
|
||||
<next>
|
||||
<block type="text_print" id="d,aouAR0nE80mk6qTAti">
|
||||
<value name="TEXT">
|
||||
<shadow type="text" id="Yr%NvOOvCnrBP8}m]bn`">
|
||||
<field name="TEXT">Point reached. Going back.</field>
|
||||
</shadow>
|
||||
</value>
|
||||
<next>
|
||||
<block type="procedures_callnoreturn" id="B0o:6T%+wpg{O%s27:bH">
|
||||
<mutation name="navigate to memorized position"></mutation>
|
||||
<next>
|
||||
<block type="land" id="~%g;%HDPtF!lqHY}KO@/">
|
||||
<field name="WAIT">TRUE</field>
|
||||
</block>
|
||||
</next>
|
||||
</block>
|
||||
</next>
|
||||
</block>
|
||||
</next>
|
||||
</block>
|
||||
</next>
|
||||
</block>
|
||||
</next>
|
||||
</block>
|
||||
<block type="procedures_defnoreturn" id="POzAJb%[yRgBrEn9K*x{" x="587" y="362">
|
||||
<field name="NAME">navigate to memorized position</field>
|
||||
<comment pinned="false" h="80" w="160">Describe this function...</comment>
|
||||
<statement name="STACK">
|
||||
<block type="navigate" id="VX|`@L*bU=aY`4!l=Pbw">
|
||||
<field name="FRAME_ID">BODY</field>
|
||||
<field name="WAIT">TRUE</field>
|
||||
<value name="X">
|
||||
<shadow type="math_number" id="c$==spjA=Vin//l1(1V@">
|
||||
<field name="NUM">0</field>
|
||||
</shadow>
|
||||
<block type="variables_get" id="LxP$oVs*8[{CH4o^RY._">
|
||||
<field name="VAR" id="MEu_bi$Xk5e(#Q`Yu=k0">start_x</field>
|
||||
</block>
|
||||
</value>
|
||||
<value name="Y">
|
||||
<shadow type="math_number" id="a)/FEG4j=.584f/:2$?H">
|
||||
<field name="NUM">0</field>
|
||||
</shadow>
|
||||
<block type="variables_get" id="_-Ib6#usbp0NS}DZ7OGS">
|
||||
<field name="VAR" id="GtS.)8^|(~RL*T4.~#VV">start_y</field>
|
||||
</block>
|
||||
</value>
|
||||
<value name="Z">
|
||||
<shadow type="math_number" id="q*MDfPe,V]rfhC1pnltq">
|
||||
<field name="NUM">0</field>
|
||||
</shadow>
|
||||
<block type="variables_get" id="VY4xW2Y|=*AH3`s2C@)5">
|
||||
<field name="VAR" id="jksdQ,]0F47Xan8{_(?+">start_z</field>
|
||||
</block>
|
||||
</value>
|
||||
<value name="ID">
|
||||
<shadow type="math_number" id="OiuYE,a3PqUW.vst+Qc$">
|
||||
<field name="NUM">0</field>
|
||||
</shadow>
|
||||
</value>
|
||||
<value name="SPEED">
|
||||
<shadow type="math_number" id="X2Ou?:=kt:`aOq,#Q-)+">
|
||||
<field name="NUM">0.5</field>
|
||||
</shadow>
|
||||
</value>
|
||||
</block>
|
||||
</statement>
|
||||
</block>
|
||||
</xml>
|
||||
91
clover_blocks/programs/examples/led-compass.xml
Normal file
@@ -0,0 +1,91 @@
|
||||
<xml xmlns="https://developers.google.com/blockly/xml">
|
||||
<block type="controls_whileUntil" id="U1it{GcGuSS:=[xiwZr1" x="113" y="113">
|
||||
<field name="MODE">WHILE</field>
|
||||
<value name="BOOL">
|
||||
<block type="logic_boolean" id="]7ZDRwde}/RqjQCX}aVW">
|
||||
<field name="BOOL">TRUE</field>
|
||||
</block>
|
||||
</value>
|
||||
<statement name="DO">
|
||||
<block type="set_effect" id="WI0zqOz/z3].cR/6UWHn">
|
||||
<field name="EFFECT">FILL</field>
|
||||
<value name="COLOR">
|
||||
<shadow type="colour_picker" id="B`6;Xv{s2TFp8Yd=ZpSD">
|
||||
<field name="COLOUR">#000000</field>
|
||||
</shadow>
|
||||
</value>
|
||||
<next>
|
||||
<block type="set_led" id="^Vcs}ki?#ctf7rAchix$">
|
||||
<value name="INDEX">
|
||||
<shadow type="math_number" id="U;VWW$[*LOF7Gf,~?YR7">
|
||||
<field name="NUM">0</field>
|
||||
</shadow>
|
||||
<block type="math_arithmetic" id="AI6PZBd`]_Z%_~4c-%dB">
|
||||
<field name="OP">MULTIPLY</field>
|
||||
<value name="A">
|
||||
<shadow type="math_number" id="|p}X]`SedK3).F/;}NlB">
|
||||
<field name="NUM">1</field>
|
||||
</shadow>
|
||||
<block type="math_arithmetic" id="-haE#:,cg{-J=NZERA;F">
|
||||
<field name="OP">DIVIDE</field>
|
||||
<value name="A">
|
||||
<shadow type="math_number" id="::st;ot}[r]csqceURu*">
|
||||
<field name="NUM">1</field>
|
||||
</shadow>
|
||||
<block type="math_arithmetic" id="a%+LN)F~=Igg+,p02[qo">
|
||||
<field name="OP">ADD</field>
|
||||
<value name="A">
|
||||
<shadow type="math_number" id="*yIGN((y)/^z0:f5:VDw">
|
||||
<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>
|
||||
</value>
|
||||
</block>
|
||||
</value>
|
||||
<value name="B">
|
||||
<shadow type="math_number" id="Wo1/ZCeir,u6/.e1H+BB">
|
||||
<field name="NUM">360</field>
|
||||
</shadow>
|
||||
</value>
|
||||
</block>
|
||||
</value>
|
||||
<value name="B">
|
||||
<shadow type="math_number" id="jENTcXz0C5/=)Xpd!}LL">
|
||||
<field name="NUM">1</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>
|
||||
</value>
|
||||
</block>
|
||||
</next>
|
||||
</block>
|
||||
</next>
|
||||
</block>
|
||||
</statement>
|
||||
</block>
|
||||
</xml>
|
||||
30
clover_blocks/programs/examples/led.xml
Normal file
@@ -0,0 +1,30 @@
|
||||
<xml xmlns="https://developers.google.com/blockly/xml">
|
||||
<block type="controls_whileUntil" id="A:_Z_27?K?HlScug%u|5" x="113" y="113">
|
||||
<field name="MODE">WHILE</field>
|
||||
<value name="BOOL">
|
||||
<block type="logic_boolean" id="/rlzePJ6XJcv22J(Q4bs">
|
||||
<field name="BOOL">TRUE</field>
|
||||
</block>
|
||||
</value>
|
||||
<statement name="DO">
|
||||
<block type="set_effect" id="GT~AX(j]r)u^,f_n0agS">
|
||||
<field name="EFFECT">WIPE</field>
|
||||
<value name="COLOR">
|
||||
<shadow type="colour_picker" id="G`I)ZAuIGcnWNyO@N(sH">
|
||||
<field name="COLOUR">#ff0000</field>
|
||||
</shadow>
|
||||
<block type="colour_random" id="}(${|~%[}eJ.QUY?FWi_"></block>
|
||||
</value>
|
||||
<next>
|
||||
<block type="wait" id="Ux(J;l+?5Gq2n^*!jXj^">
|
||||
<value name="TIME">
|
||||
<shadow type="math_number" id=")As9bASkedr9x@M)*)Pf">
|
||||
<field name="NUM">1</field>
|
||||
</shadow>
|
||||
</value>
|
||||
</block>
|
||||
</next>
|
||||
</block>
|
||||
</statement>
|
||||
</block>
|
||||
</xml>
|
||||
29
clover_blocks/programs/examples/print-range.xml
Normal file
@@ -0,0 +1,29 @@
|
||||
<xml xmlns="https://developers.google.com/blockly/xml">
|
||||
<block type="controls_whileUntil" id="^{D$=!y=ahJx0.^n?Ycr" x="88" y="137">
|
||||
<field name="MODE">WHILE</field>
|
||||
<value name="BOOL">
|
||||
<block type="logic_boolean" id="a;~UtFPf9O3B)#QBJxL6">
|
||||
<field name="BOOL">TRUE</field>
|
||||
</block>
|
||||
</value>
|
||||
<statement name="DO">
|
||||
<block type="text_print" id="doqF#i]/ulE{Z0l/{9`K">
|
||||
<value name="TEXT">
|
||||
<shadow type="text" id="Y$c,rIaw^bNs2wIw%[^(">
|
||||
<field name="TEXT">abc</field>
|
||||
</shadow>
|
||||
<block type="rangefinder_distance" id="Pi+WekHZvZ0p}JY-^CLQ"></block>
|
||||
</value>
|
||||
<next>
|
||||
<block type="wait" id="=$,8TaKwL75Pb,_tsCVU">
|
||||
<value name="TIME">
|
||||
<shadow type="math_number" id="/r+hzH#G0Ru#ES+}MxUl">
|
||||
<field name="NUM">0.5</field>
|
||||
</shadow>
|
||||
</value>
|
||||
</block>
|
||||
</next>
|
||||
</block>
|
||||
</statement>
|
||||
</block>
|
||||
</xml>
|
||||
88
clover_blocks/programs/examples/rotation.xml
Normal file
@@ -0,0 +1,88 @@
|
||||
<xml xmlns="https://developers.google.com/blockly/xml">
|
||||
<block type="take_off" id="R@=3~Fq;AxFaRO{ZDFUM" x="162" y="112">
|
||||
<field name="WAIT">TRUE</field>
|
||||
<value name="ALT">
|
||||
<shadow type="math_number" id="cf8/,N48N;Fvn@EWB%,B">
|
||||
<field name="NUM">1</field>
|
||||
</shadow>
|
||||
</value>
|
||||
<next>
|
||||
<block type="navigate" id="[r%uJ2rw#3j.sLSBFf`N">
|
||||
<field name="FRAME_ID">BODY</field>
|
||||
<field name="WAIT">TRUE</field>
|
||||
<value name="X">
|
||||
<shadow type="math_number" id="5;@1vq|;OnlHl#FFDm/}">
|
||||
<field name="NUM">1</field>
|
||||
</shadow>
|
||||
</value>
|
||||
<value name="Y">
|
||||
<shadow type="math_number" id="Jhe8@=gRxwj0oO*Q1F7V">
|
||||
<field name="NUM">0</field>
|
||||
</shadow>
|
||||
</value>
|
||||
<value name="Z">
|
||||
<shadow type="math_number" id="wms+rWijPhnI/K++At;P">
|
||||
<field name="NUM">0</field>
|
||||
</shadow>
|
||||
</value>
|
||||
<value name="ID">
|
||||
<shadow type="math_number" id=".^-h~@m]zg3il)O.9eFy">
|
||||
<field name="NUM">0</field>
|
||||
</shadow>
|
||||
</value>
|
||||
<value name="SPEED">
|
||||
<shadow type="math_number" id="3L3FgAO(:aZp/:V%u=P7">
|
||||
<field name="NUM">0.5</field>
|
||||
</shadow>
|
||||
</value>
|
||||
<next>
|
||||
<block type="set_yaw" id="nE,tYuHO--PmXN:*g@D%">
|
||||
<field name="FRAME_ID">body</field>
|
||||
<field name="WAIT">TRUE</field>
|
||||
<value name="YAW">
|
||||
<shadow type="angle" id="DoJ$Yj+fVT~cj=E%N:4+">
|
||||
<field name="ANGLE">180</field>
|
||||
</shadow>
|
||||
</value>
|
||||
<next>
|
||||
<block type="navigate" id="H6W4@QtAT{_xo0.fO^z4">
|
||||
<field name="FRAME_ID">BODY</field>
|
||||
<field name="WAIT">TRUE</field>
|
||||
<value name="X">
|
||||
<shadow type="math_number" id="|.KN1m1O$/3=C,WG3sx}">
|
||||
<field name="NUM">1</field>
|
||||
</shadow>
|
||||
</value>
|
||||
<value name="Y">
|
||||
<shadow type="math_number" id="oyc7mxrbA/@[_1wtPER^">
|
||||
<field name="NUM">0</field>
|
||||
</shadow>
|
||||
</value>
|
||||
<value name="Z">
|
||||
<shadow type="math_number" id="dh}ac~kErkIIFeIZB,)d">
|
||||
<field name="NUM">0</field>
|
||||
</shadow>
|
||||
</value>
|
||||
<value name="ID">
|
||||
<shadow type="math_number" id="q+{la-yiw61v9BSV-y};">
|
||||
<field name="NUM">0</field>
|
||||
</shadow>
|
||||
</value>
|
||||
<value name="SPEED">
|
||||
<shadow type="math_number" id=";dk@RJGfZ)5w*:m4kp==">
|
||||
<field name="NUM">0.5</field>
|
||||
</shadow>
|
||||
</value>
|
||||
<next>
|
||||
<block type="land" id="53Ssv6^lEHoD?tBO{5Sh">
|
||||
<field name="WAIT">TRUE</field>
|
||||
</block>
|
||||
</next>
|
||||
</block>
|
||||
</next>
|
||||
</block>
|
||||
</next>
|
||||
</block>
|
||||
</next>
|
||||
</block>
|
||||
</xml>
|
||||
86
clover_blocks/programs/examples/simple-flight.xml
Normal file
@@ -0,0 +1,86 @@
|
||||
<xml xmlns="https://developers.google.com/blockly/xml">
|
||||
<block type="take_off" id="R@=3~Fq;AxFaRO{ZDFUM" x="62" y="88">
|
||||
<field name="WAIT">TRUE</field>
|
||||
<value name="ALT">
|
||||
<shadow type="math_number" id="cf8/,N48N;Fvn@EWB%,B">
|
||||
<field name="NUM">1</field>
|
||||
</shadow>
|
||||
<block type="text_prompt_ext" id="#BO!OX5u-GHwsu!KzBT5">
|
||||
<mutation type="NUMBER"></mutation>
|
||||
<field name="TYPE">NUMBER</field>
|
||||
<value name="TEXT">
|
||||
<shadow type="text" id="unay$W?6.WiDB!|[3GN3">
|
||||
<field name="TEXT">Enter flight altitude</field>
|
||||
</shadow>
|
||||
</value>
|
||||
</block>
|
||||
</value>
|
||||
<next>
|
||||
<block type="navigate" id="BOHP@mRbJamp}]6/yc,n">
|
||||
<field name="FRAME_ID">BODY</field>
|
||||
<field name="WAIT">TRUE</field>
|
||||
<value name="X">
|
||||
<shadow type="math_number" id="hzjq`v(`k6vZN],.8%Hf">
|
||||
<field name="NUM">1</field>
|
||||
</shadow>
|
||||
</value>
|
||||
<value name="Y">
|
||||
<shadow type="math_number" id="FIVk1Hm_+CU8XB~t@?S;">
|
||||
<field name="NUM">0</field>
|
||||
</shadow>
|
||||
</value>
|
||||
<value name="Z">
|
||||
<shadow type="math_number" id="B{LoNO6}MgJ.JeN+8]tR">
|
||||
<field name="NUM">0</field>
|
||||
</shadow>
|
||||
</value>
|
||||
<value name="ID">
|
||||
<shadow type="math_number" id="w!F}PhAG[Gn;5XsIg$XL">
|
||||
<field name="NUM">0</field>
|
||||
</shadow>
|
||||
</value>
|
||||
<value name="SPEED">
|
||||
<shadow type="math_number" id="AjhS9Wf?M`%}A(H_bW9K">
|
||||
<field name="NUM">0.5</field>
|
||||
</shadow>
|
||||
</value>
|
||||
<next>
|
||||
<block type="navigate" id="|Aa[hh]OAUS+b7I?;3VJ">
|
||||
<field name="FRAME_ID">BODY</field>
|
||||
<field name="WAIT">TRUE</field>
|
||||
<value name="X">
|
||||
<shadow type="math_number" id="=n#)78Bd*!iJyzF=dSA*">
|
||||
<field name="NUM">-1</field>
|
||||
</shadow>
|
||||
</value>
|
||||
<value name="Y">
|
||||
<shadow type="math_number" id="YqC+GQF/[G=li}/s_o)q">
|
||||
<field name="NUM">0</field>
|
||||
</shadow>
|
||||
</value>
|
||||
<value name="Z">
|
||||
<shadow type="math_number" id="~xsT!Ug+uMeU5F/Y4;k5">
|
||||
<field name="NUM">0</field>
|
||||
</shadow>
|
||||
</value>
|
||||
<value name="ID">
|
||||
<shadow type="math_number" id="%WRn|02iTTwCG:zB}dSf">
|
||||
<field name="NUM">0</field>
|
||||
</shadow>
|
||||
</value>
|
||||
<value name="SPEED">
|
||||
<shadow type="math_number" id="A#q.M,b1D*,13Ldp.F2w">
|
||||
<field name="NUM">0.5</field>
|
||||
</shadow>
|
||||
</value>
|
||||
<next>
|
||||
<block type="land" id="_U*W_q1)l+l@#^TC%w)w">
|
||||
<field name="WAIT">TRUE</field>
|
||||
</block>
|
||||
</next>
|
||||
</block>
|
||||
</next>
|
||||
</block>
|
||||
</next>
|
||||
</block>
|
||||
</xml>
|
||||
60
clover_blocks/programs/examples/takeoff-land.xml
Normal file
@@ -0,0 +1,60 @@
|
||||
<xml xmlns="https://developers.google.com/blockly/xml">
|
||||
<block type="text_print" id="2p:*N].+8c=|ZJXCWVn[" x="162" y="88">
|
||||
<value name="TEXT">
|
||||
<shadow type="text" id="9H+7z4A.pZ:Zz)7}H3Y7">
|
||||
<field name="TEXT">Start mission</field>
|
||||
</shadow>
|
||||
</value>
|
||||
<next>
|
||||
<block type="take_off" id="R@=3~Fq;AxFaRO{ZDFUM">
|
||||
<field name="WAIT">TRUE</field>
|
||||
<value name="ALT">
|
||||
<shadow type="math_number" id="cf8/,N48N;Fvn@EWB%,B">
|
||||
<field name="NUM">1</field>
|
||||
</shadow>
|
||||
</value>
|
||||
<next>
|
||||
<block type="text_print" id="|Tdajnf]Rz@ajSW`0Skv">
|
||||
<value name="TEXT">
|
||||
<shadow type="text" id="Wqr:Hf~r2d.A%S7%%4.)">
|
||||
<field name="TEXT">Take off complete, wait</field>
|
||||
</shadow>
|
||||
</value>
|
||||
<next>
|
||||
<block type="wait" id="-]MH9NMT#N-w!5yI1$F)">
|
||||
<value name="TIME">
|
||||
<shadow type="math_number" id="?k~ZUNcrx-iC;LFmarbm">
|
||||
<field name="NUM">3</field>
|
||||
</shadow>
|
||||
</value>
|
||||
<next>
|
||||
<block type="text_print" id="SXJsfN{P13FL~n9;|%P:">
|
||||
<value name="TEXT">
|
||||
<shadow type="text" id="[Z5,f|El:VX5zcRaMtXa">
|
||||
<field name="TEXT">Land</field>
|
||||
</shadow>
|
||||
</value>
|
||||
<next>
|
||||
<block type="land" id="G5+Fs.6Y4(K9Dw`wjgua">
|
||||
<field name="WAIT">TRUE</field>
|
||||
<next>
|
||||
<block type="text_print" id="o?bvXARz^4_U0oXC-#.V">
|
||||
<value name="TEXT">
|
||||
<shadow type="text" id="`tadiS,[OZ`#f:=u.:9~">
|
||||
<field name="TEXT">Mission finished</field>
|
||||
</shadow>
|
||||
</value>
|
||||
</block>
|
||||
</next>
|
||||
</block>
|
||||
</next>
|
||||
</block>
|
||||
</next>
|
||||
</block>
|
||||
</next>
|
||||
</block>
|
||||
</next>
|
||||
</block>
|
||||
</next>
|
||||
</block>
|
||||
</xml>
|
||||
137
clover_blocks/programs/examples/variables.xml
Normal file
@@ -0,0 +1,137 @@
|
||||
<xml xmlns="https://developers.google.com/blockly/xml">
|
||||
<variables>
|
||||
<variable id="]gc9ItU#$!=G*S._3$n~">start_x</variable>
|
||||
<variable id="D9Oy(29I!!k9+(#zI,4}">start_y</variable>
|
||||
</variables>
|
||||
<block type="take_off" id="X]W2Bs=WFxFsco{Yr`bH" x="87" y="88">
|
||||
<field name="WAIT">TRUE</field>
|
||||
<value name="ALT">
|
||||
<shadow type="math_number" id="{7ezr;C@IT-IJ3ylt?];">
|
||||
<field name="NUM">1.5</field>
|
||||
</shadow>
|
||||
</value>
|
||||
<next>
|
||||
<block type="variables_set" id="IWR_j|7pUxrIGrxGLP#Z">
|
||||
<field name="VAR" id="]gc9ItU#$!=G*S._3$n~">start_x</field>
|
||||
<value name="VALUE">
|
||||
<block type="get_position" id="ze{FI]Vv*E3kZ1Zw6Bmn">
|
||||
<field name="FIELD">X</field>
|
||||
<field name="FRAME_ID">ARUCO_MAP</field>
|
||||
<value name="ID">
|
||||
<shadow type="math_number" id="s~^V?k;dKa(($OG9mAK)">
|
||||
<field name="NUM">0</field>
|
||||
</shadow>
|
||||
</value>
|
||||
</block>
|
||||
</value>
|
||||
<next>
|
||||
<block type="variables_set" id="s3rE=-6+;f(Lua_uKGY[">
|
||||
<field name="VAR" id="D9Oy(29I!!k9+(#zI,4}">start_y</field>
|
||||
<value name="VALUE">
|
||||
<block type="get_position" id="?t+jp;7Bk#wzoz=DY{sO">
|
||||
<field name="FIELD">Y</field>
|
||||
<field name="FRAME_ID">ARUCO_MAP</field>
|
||||
<value name="ID">
|
||||
<shadow type="math_number" id="KybjD~@_RFIx=8Dzbz4v">
|
||||
<field name="NUM">0</field>
|
||||
</shadow>
|
||||
</value>
|
||||
</block>
|
||||
</value>
|
||||
<next>
|
||||
<block type="text_print" id="|xj}5M(:.~`Vpq-GKi/0">
|
||||
<value name="TEXT">
|
||||
<shadow type="text" id="{o^2v+y6L^1#[Y8r_sdW">
|
||||
<field name="TEXT">Fly to point 0, 0</field>
|
||||
</shadow>
|
||||
</value>
|
||||
<next>
|
||||
<block type="navigate" id="-8]peWQRtTK$1X0J0w!2">
|
||||
<field name="FRAME_ID">ARUCO_MAP</field>
|
||||
<field name="WAIT">TRUE</field>
|
||||
<value name="X">
|
||||
<shadow type="math_number" id="PT`K-=?U^uL#BXouoi~G">
|
||||
<field name="NUM">0</field>
|
||||
</shadow>
|
||||
</value>
|
||||
<value name="Y">
|
||||
<shadow type="math_number" id="d_1oBZdx#`_kbWf_Qu$g">
|
||||
<field name="NUM">0</field>
|
||||
</shadow>
|
||||
</value>
|
||||
<value name="Z">
|
||||
<shadow type="math_number" id="}Y,E=*pJaG+HOSB*f=aX">
|
||||
<field name="NUM">1.5</field>
|
||||
</shadow>
|
||||
</value>
|
||||
<value name="ID">
|
||||
<shadow type="math_number" id=")/%?zNt|6thYwjowvbk/">
|
||||
<field name="NUM">0</field>
|
||||
</shadow>
|
||||
</value>
|
||||
<value name="SPEED">
|
||||
<shadow type="math_number" id="MH}%@OvXa*FK-Vx63RTd">
|
||||
<field name="NUM">0.5</field>
|
||||
</shadow>
|
||||
</value>
|
||||
<next>
|
||||
<block type="text_print" id="IVsd5hFEwp@V?3f02p},">
|
||||
<value name="TEXT">
|
||||
<shadow type="text" id="0gcgp`mZ,9oDTS[4vWpT">
|
||||
<field name="TEXT">Fly to initial point</field>
|
||||
</shadow>
|
||||
</value>
|
||||
<next>
|
||||
<block type="navigate" id=":;b$YH+6#3h/_$Fa}0w_">
|
||||
<field name="FRAME_ID">ARUCO_MAP</field>
|
||||
<field name="WAIT">TRUE</field>
|
||||
<value name="X">
|
||||
<shadow type="math_number" id=";GL$bb^Yu;vQrhxy(o:S">
|
||||
<field name="NUM">0</field>
|
||||
</shadow>
|
||||
<block type="variables_get" id="tsqWR~saO6UU^*iLmDZ(">
|
||||
<field name="VAR" id="]gc9ItU#$!=G*S._3$n~">start_x</field>
|
||||
</block>
|
||||
</value>
|
||||
<value name="Y">
|
||||
<shadow type="math_number" id="y5|y58G[s-,qnfB/@Xr%">
|
||||
<field name="NUM">0</field>
|
||||
</shadow>
|
||||
<block type="variables_get" id="Hfzk#prb}M2BbEWIAX3k">
|
||||
<field name="VAR" id="D9Oy(29I!!k9+(#zI,4}">start_y</field>
|
||||
</block>
|
||||
</value>
|
||||
<value name="Z">
|
||||
<shadow type="math_number" id="B%NGa`:z=[Kpij2$0p}T">
|
||||
<field name="NUM">1.5</field>
|
||||
</shadow>
|
||||
</value>
|
||||
<value name="ID">
|
||||
<shadow type="math_number" id="KaLkf?/NkD_7q@=J1G|I">
|
||||
<field name="NUM">0</field>
|
||||
</shadow>
|
||||
</value>
|
||||
<value name="SPEED">
|
||||
<shadow type="math_number" id="Agwx#kYhdE}!dY!St:L1">
|
||||
<field name="NUM">0.5</field>
|
||||
</shadow>
|
||||
</value>
|
||||
<next>
|
||||
<block type="land" id="8y]p?)Zm2}*+;0HP]p1$">
|
||||
<field name="WAIT">TRUE</field>
|
||||
</block>
|
||||
</next>
|
||||
</block>
|
||||
</next>
|
||||
</block>
|
||||
</next>
|
||||
</block>
|
||||
</next>
|
||||
</block>
|
||||
</next>
|
||||
</block>
|
||||
</next>
|
||||
</block>
|
||||
</next>
|
||||
</block>
|
||||
</xml>
|
||||
BIN
clover_blocks/screenshot.png
Normal file
|
After Width: | Height: | Size: 182 KiB |
184
clover_blocks/src/clover_blocks
Executable file
@@ -0,0 +1,184 @@
|
||||
#!/usr/bin/env python
|
||||
|
||||
# Copyright (C) 2020 Copter Express Technologies
|
||||
#
|
||||
# Author: Oleg Kalachev <okalachev@gmail.com>
|
||||
#
|
||||
# Distributed under MIT License (available at https://opensource.org/licenses/MIT).
|
||||
# The above copyright notice and this permission notice shall be included in all
|
||||
# copies or substantial portions of the Software.
|
||||
|
||||
from __future__ import print_function
|
||||
|
||||
import rospy
|
||||
import os
|
||||
import threading
|
||||
import re
|
||||
import uuid
|
||||
from std_msgs.msg import Bool, String
|
||||
from std_srvs.srv import Trigger
|
||||
from clover_blocks.msg import Prompt
|
||||
from clover_blocks.srv import Run, Load, Store
|
||||
|
||||
|
||||
rospy.init_node('clover_blocks')
|
||||
|
||||
stop = None
|
||||
block = ''
|
||||
published_block = None
|
||||
running_lock = threading.Lock()
|
||||
|
||||
running_pub = rospy.Publisher('~running', Bool, queue_size=1, latch=True)
|
||||
block_pub = rospy.Publisher('~block', String, queue_size=1, latch=True)
|
||||
print_pub = rospy.Publisher('~print', String, queue_size=10)
|
||||
prompt_pub = rospy.Publisher('~prompt', Prompt, queue_size=10)
|
||||
error_pub = rospy.Publisher('~error', String, queue_size=10)
|
||||
|
||||
|
||||
running_pub.publish(False)
|
||||
|
||||
|
||||
class Stop(Exception):
|
||||
pass
|
||||
|
||||
|
||||
def publish_block(event):
|
||||
global published_block, block
|
||||
if published_block != block:
|
||||
block_pub.publish(block)
|
||||
published_block = block
|
||||
|
||||
|
||||
rospy.Timer(rospy.Duration(rospy.get_param('block_rate', 0.2)), publish_block)
|
||||
|
||||
|
||||
def change_block(_block):
|
||||
global block
|
||||
block = _block
|
||||
if stop: raise Stop
|
||||
|
||||
|
||||
rospy_sleep = rospy.sleep
|
||||
|
||||
|
||||
def sleep(duration):
|
||||
time_start = rospy.get_time()
|
||||
|
||||
if isinstance(duration, rospy.Duration):
|
||||
duration = duration.to_sec()
|
||||
|
||||
time_until = time_start + duration
|
||||
|
||||
while not rospy.is_shutdown():
|
||||
if stop: raise Stop # check stop condition every half-second
|
||||
if (time_until - rospy.get_time()) > 0.5:
|
||||
print('sleep 0.5')
|
||||
rospy_sleep(0.5)
|
||||
else:
|
||||
rospy_sleep(time_until - rospy.get_time())
|
||||
return
|
||||
|
||||
|
||||
rospy.sleep = sleep
|
||||
rospy.init_node = lambda *args, **kwargs: None
|
||||
|
||||
|
||||
def _print(s):
|
||||
rospy.loginfo(str(s))
|
||||
print_pub.publish(str(s))
|
||||
|
||||
|
||||
def _input(s):
|
||||
rospy.loginfo('Input with message %s', s)
|
||||
prompt_id = str(uuid.uuid4()).replace('-', '')
|
||||
prompt_pub.publish(message=str(s), id=prompt_id)
|
||||
return rospy.wait_for_message('~input/' + prompt_id, String, timeout=30).data;
|
||||
|
||||
|
||||
def run(req):
|
||||
if not running_lock.acquire(False):
|
||||
return {'message': 'Already running'}
|
||||
|
||||
try:
|
||||
rospy.loginfo('Run program')
|
||||
running_pub.publish(True)
|
||||
|
||||
def program_thread():
|
||||
global stop
|
||||
stop = False
|
||||
g = {'rospy': rospy,
|
||||
'_b': change_block,
|
||||
'print': _print,
|
||||
'raw_input': _input}
|
||||
try:
|
||||
exec req.code in g
|
||||
except Stop:
|
||||
rospy.loginfo('Program forced to stop')
|
||||
except Exception as e:
|
||||
rospy.logerr(str(e))
|
||||
error_pub.publish(str(e))
|
||||
|
||||
rospy.loginfo('Program terminated')
|
||||
running_lock.release()
|
||||
running_pub.publish(False)
|
||||
change_block('')
|
||||
|
||||
t = threading.Thread(target=program_thread)
|
||||
t.start()
|
||||
|
||||
return {'success': True}
|
||||
|
||||
except Exception as e:
|
||||
running_lock.release()
|
||||
return {'message': str(e)}
|
||||
|
||||
|
||||
def stop(req):
|
||||
global stop
|
||||
rospy.loginfo('Stop program')
|
||||
stop = True
|
||||
return {'success': True}
|
||||
|
||||
|
||||
programs_path = rospy.get_param('~programs_dir', os.path.dirname(os.path.abspath(__file__)) + '/../programs')
|
||||
|
||||
|
||||
def load(req):
|
||||
res = {'names': [], 'programs': [], 'success': True}
|
||||
try:
|
||||
for currentpath, folders, files in os.walk(programs_path):
|
||||
for f in files:
|
||||
if not f.endswith('.xml'):
|
||||
continue
|
||||
filename = os.path.join(currentpath, f)
|
||||
res['names'].append(os.path.relpath(filename, programs_path))
|
||||
res['programs'].append(open(filename, 'r').read())
|
||||
return res
|
||||
except Exception as e:
|
||||
rospy.logerr(e)
|
||||
return {'names': [], 'programs': [], 'message': str(e)}
|
||||
|
||||
|
||||
name_regexp = re.compile(r'^[a-zA-Z-_.]{0,20}$')
|
||||
|
||||
def store(req):
|
||||
if not name_regexp.match(req.name):
|
||||
return {'message': 'Bad program name'}
|
||||
|
||||
filename = os.path.abspath(os.path.join(programs_path, req.name))
|
||||
try:
|
||||
open(filename, 'w').write(req.program)
|
||||
return {'success': True, 'message': 'Stored to ' + filename}
|
||||
except Exception as e:
|
||||
rospy.logerr(e)
|
||||
return {'names': [], 'programs': [], 'message': str(e)}
|
||||
|
||||
|
||||
rospy.Service('~run', Run, run)
|
||||
rospy.Service('~stop', Trigger, stop)
|
||||
rospy.Service('~load', Load, load)
|
||||
rospy.Service('~store', Store, store)
|
||||
|
||||
|
||||
rospy.loginfo('Ready')
|
||||
rospy.spin()
|
||||
5
clover_blocks/srv/Load.srv
Normal file
@@ -0,0 +1,5 @@
|
||||
---
|
||||
bool success
|
||||
string message
|
||||
string[] names
|
||||
string[] programs
|
||||
4
clover_blocks/srv/Run.srv
Normal file
@@ -0,0 +1,4 @@
|
||||
string code # code in Python
|
||||
---
|
||||
bool success
|
||||
string message
|
||||
5
clover_blocks/srv/Store.srv
Normal file
@@ -0,0 +1,5 @@
|
||||
string name
|
||||
string program
|
||||
---
|
||||
bool success
|
||||
string message
|
||||
202
clover_blocks/www/blockly/LICENSE
Executable file
@@ -0,0 +1,202 @@
|
||||
|
||||
Apache License
|
||||
Version 2.0, January 2004
|
||||
http://www.apache.org/licenses/
|
||||
|
||||
TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
|
||||
|
||||
1. Definitions.
|
||||
|
||||
"License" shall mean the terms and conditions for use, reproduction,
|
||||
and distribution as defined by Sections 1 through 9 of this document.
|
||||
|
||||
"Licensor" shall mean the copyright owner or entity authorized by
|
||||
the copyright owner that is granting the License.
|
||||
|
||||
"Legal Entity" shall mean the union of the acting entity and all
|
||||
other entities that control, are controlled by, or are under common
|
||||
control with that entity. For the purposes of this definition,
|
||||
"control" means (i) the power, direct or indirect, to cause the
|
||||
direction or management of such entity, whether by contract or
|
||||
otherwise, or (ii) ownership of fifty percent (50%) or more of the
|
||||
outstanding shares, or (iii) beneficial ownership of such entity.
|
||||
|
||||
"You" (or "Your") shall mean an individual or Legal Entity
|
||||
exercising permissions granted by this License.
|
||||
|
||||
"Source" form shall mean the preferred form for making modifications,
|
||||
including but not limited to software source code, documentation
|
||||
source, and configuration files.
|
||||
|
||||
"Object" form shall mean any form resulting from mechanical
|
||||
transformation or translation of a Source form, including but
|
||||
not limited to compiled object code, generated documentation,
|
||||
and conversions to other media types.
|
||||
|
||||
"Work" shall mean the work of authorship, whether in Source or
|
||||
Object form, made available under the License, as indicated by a
|
||||
copyright notice that is included in or attached to the work
|
||||
(an example is provided in the Appendix below).
|
||||
|
||||
"Derivative Works" shall mean any work, whether in Source or Object
|
||||
form, that is based on (or derived from) the Work and for which the
|
||||
editorial revisions, annotations, elaborations, or other modifications
|
||||
represent, as a whole, an original work of authorship. For the purposes
|
||||
of this License, Derivative Works shall not include works that remain
|
||||
separable from, or merely link (or bind by name) to the interfaces of,
|
||||
the Work and Derivative Works thereof.
|
||||
|
||||
"Contribution" shall mean any work of authorship, including
|
||||
the original version of the Work and any modifications or additions
|
||||
to that Work or Derivative Works thereof, that is intentionally
|
||||
submitted to Licensor for inclusion in the Work by the copyright owner
|
||||
or by an individual or Legal Entity authorized to submit on behalf of
|
||||
the copyright owner. For the purposes of this definition, "submitted"
|
||||
means any form of electronic, verbal, or written communication sent
|
||||
to the Licensor or its representatives, including but not limited to
|
||||
communication on electronic mailing lists, source code control systems,
|
||||
and issue tracking systems that are managed by, or on behalf of, the
|
||||
Licensor for the purpose of discussing and improving the Work, but
|
||||
excluding communication that is conspicuously marked or otherwise
|
||||
designated in writing by the copyright owner as "Not a Contribution."
|
||||
|
||||
"Contributor" shall mean Licensor and any individual or Legal Entity
|
||||
on behalf of whom a Contribution has been received by Licensor and
|
||||
subsequently incorporated within the Work.
|
||||
|
||||
2. Grant of Copyright License. Subject to the terms and conditions of
|
||||
this License, each Contributor hereby grants to You a perpetual,
|
||||
worldwide, non-exclusive, no-charge, royalty-free, irrevocable
|
||||
copyright license to reproduce, prepare Derivative Works of,
|
||||
publicly display, publicly perform, sublicense, and distribute the
|
||||
Work and such Derivative Works in Source or Object form.
|
||||
|
||||
3. Grant of Patent License. Subject to the terms and conditions of
|
||||
this License, each Contributor hereby grants to You a perpetual,
|
||||
worldwide, non-exclusive, no-charge, royalty-free, irrevocable
|
||||
(except as stated in this section) patent license to make, have made,
|
||||
use, offer to sell, sell, import, and otherwise transfer the Work,
|
||||
where such license applies only to those patent claims licensable
|
||||
by such Contributor that are necessarily infringed by their
|
||||
Contribution(s) alone or by combination of their Contribution(s)
|
||||
with the Work to which such Contribution(s) was submitted. If You
|
||||
institute patent litigation against any entity (including a
|
||||
cross-claim or counterclaim in a lawsuit) alleging that the Work
|
||||
or a Contribution incorporated within the Work constitutes direct
|
||||
or contributory patent infringement, then any patent licenses
|
||||
granted to You under this License for that Work shall terminate
|
||||
as of the date such litigation is filed.
|
||||
|
||||
4. Redistribution. You may reproduce and distribute copies of the
|
||||
Work or Derivative Works thereof in any medium, with or without
|
||||
modifications, and in Source or Object form, provided that You
|
||||
meet the following conditions:
|
||||
|
||||
(a) You must give any other recipients of the Work or
|
||||
Derivative Works a copy of this License; and
|
||||
|
||||
(b) You must cause any modified files to carry prominent notices
|
||||
stating that You changed the files; and
|
||||
|
||||
(c) You must retain, in the Source form of any Derivative Works
|
||||
that You distribute, all copyright, patent, trademark, and
|
||||
attribution notices from the Source form of the Work,
|
||||
excluding those notices that do not pertain to any part of
|
||||
the Derivative Works; and
|
||||
|
||||
(d) If the Work includes a "NOTICE" text file as part of its
|
||||
distribution, then any Derivative Works that You distribute must
|
||||
include a readable copy of the attribution notices contained
|
||||
within such NOTICE file, excluding those notices that do not
|
||||
pertain to any part of the Derivative Works, in at least one
|
||||
of the following places: within a NOTICE text file distributed
|
||||
as part of the Derivative Works; within the Source form or
|
||||
documentation, if provided along with the Derivative Works; or,
|
||||
within a display generated by the Derivative Works, if and
|
||||
wherever such third-party notices normally appear. The contents
|
||||
of the NOTICE file are for informational purposes only and
|
||||
do not modify the License. You may add Your own attribution
|
||||
notices within Derivative Works that You distribute, alongside
|
||||
or as an addendum to the NOTICE text from the Work, provided
|
||||
that such additional attribution notices cannot be construed
|
||||
as modifying the License.
|
||||
|
||||
You may add Your own copyright statement to Your modifications and
|
||||
may provide additional or different license terms and conditions
|
||||
for use, reproduction, or distribution of Your modifications, or
|
||||
for any such Derivative Works as a whole, provided Your use,
|
||||
reproduction, and distribution of the Work otherwise complies with
|
||||
the conditions stated in this License.
|
||||
|
||||
5. Submission of Contributions. Unless You explicitly state otherwise,
|
||||
any Contribution intentionally submitted for inclusion in the Work
|
||||
by You to the Licensor shall be under the terms and conditions of
|
||||
this License, without any additional terms or conditions.
|
||||
Notwithstanding the above, nothing herein shall supersede or modify
|
||||
the terms of any separate license agreement you may have executed
|
||||
with Licensor regarding such Contributions.
|
||||
|
||||
6. Trademarks. This License does not grant permission to use the trade
|
||||
names, trademarks, service marks, or product names of the Licensor,
|
||||
except as required for reasonable and customary use in describing the
|
||||
origin of the Work and reproducing the content of the NOTICE file.
|
||||
|
||||
7. Disclaimer of Warranty. Unless required by applicable law or
|
||||
agreed to in writing, Licensor provides the Work (and each
|
||||
Contributor provides its Contributions) on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
|
||||
implied, including, without limitation, any warranties or conditions
|
||||
of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
|
||||
PARTICULAR PURPOSE. You are solely responsible for determining the
|
||||
appropriateness of using or redistributing the Work and assume any
|
||||
risks associated with Your exercise of permissions under this License.
|
||||
|
||||
8. Limitation of Liability. In no event and under no legal theory,
|
||||
whether in tort (including negligence), contract, or otherwise,
|
||||
unless required by applicable law (such as deliberate and grossly
|
||||
negligent acts) or agreed to in writing, shall any Contributor be
|
||||
liable to You for damages, including any direct, indirect, special,
|
||||
incidental, or consequential damages of any character arising as a
|
||||
result of this License or out of the use or inability to use the
|
||||
Work (including but not limited to damages for loss of goodwill,
|
||||
work stoppage, computer failure or malfunction, or any and all
|
||||
other commercial damages or losses), even if such Contributor
|
||||
has been advised of the possibility of such damages.
|
||||
|
||||
9. Accepting Warranty or Additional Liability. While redistributing
|
||||
the Work or Derivative Works thereof, You may choose to offer,
|
||||
and charge a fee for, acceptance of support, warranty, indemnity,
|
||||
or other liability obligations and/or rights consistent with this
|
||||
License. However, in accepting such obligations, You may act only
|
||||
on Your own behalf and on Your sole responsibility, not on behalf
|
||||
of any other Contributor, and only if You agree to indemnify,
|
||||
defend, and hold each Contributor harmless for any liability
|
||||
incurred by, or claims asserted against, such Contributor by reason
|
||||
of your accepting any such warranty or additional liability.
|
||||
|
||||
END OF TERMS AND CONDITIONS
|
||||
|
||||
APPENDIX: How to apply the Apache License to your work.
|
||||
|
||||
To apply the Apache License to your work, attach the following
|
||||
boilerplate notice, with the fields enclosed by brackets "[]"
|
||||
replaced with your own identifying information. (Don't include
|
||||
the brackets!) The text should be enclosed in the appropriate
|
||||
comment syntax for the file format. We also recommend that a
|
||||
file or class name and description of purpose be included on the
|
||||
same "printed page" as the copyright notice for easier
|
||||
identification within third-party archives.
|
||||
|
||||
Copyright [yyyy] [name of copyright owner]
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
60
clover_blocks/www/blockly/README.md
Executable file
@@ -0,0 +1,60 @@
|
||||
# Blockly [](https://travis-ci.org/google/blockly)
|
||||
|
||||
|
||||
Google's Blockly is a web-based, visual programming editor. Users can drag
|
||||
blocks together to build programs. All code is free and open source.
|
||||
|
||||
**The project page is https://developers.google.com/blockly/**
|
||||
|
||||

|
||||
|
||||
Blockly has an active [developer forum](https://groups.google.com/forum/#!forum/blockly). Please drop by and say hello. Show us your prototypes early; collectively we have a lot of experience and can offer hints which will save you time. We actively monitor the forums and typically respond to questions within 2 working days.
|
||||
|
||||
Help us focus our development efforts by telling us [what you are doing with
|
||||
Blockly](https://developers.google.com/blockly/registration). The questionnaire only takes
|
||||
a few minutes and will help us better support the Blockly community.
|
||||
|
||||
Cross-browser Testing Platform and Open Source <3 Provided by [Sauce Labs](https://saucelabs.com)
|
||||
|
||||
We support IE11 and test it using [BrowserStack](https://browserstack.com)
|
||||
|
||||
Want to contribute? Great! First, read [our guidelines for contributors](https://developers.google.com/blockly/guides/modify/contributing).
|
||||
|
||||
## Releases
|
||||
|
||||
The next major release will be **June 26th, 2020**.
|
||||
|
||||
We release by pushing the latest code to the master branch, followed by updating our [docs](https://developers.google.com/blockly) and [demo pages](https://blockly-demo.appspot.com). We typically release a new version of Blockly once a quarter (every 3 months). If there are breaking bugs, such as a crash when performing a standard action or a rendering issue that makes Blockly unusable, we will cherry-pick fixes to master between releases to fix them. The [releases page](https://github.com/google/blockly/releases) has a list of all releases.
|
||||
|
||||
Releases are tagged by the release date (YYYYMMDD) with a leading '2.' and a trailing '.0' in case we ever need a major or minor version (such as [2.20190722.1](https://github.com/google/blockly/tree/2.20190722.1)). If you're using npm, you can install the ``blockly`` package on npm:
|
||||
```bash
|
||||
npm install blockly
|
||||
```
|
||||
|
||||
### New APIs
|
||||
|
||||
Once a new API is merged into master it is considered beta until the following release. We generally try to avoid changing an API after it has been merged to master, but sometimes we need to make changes after seeing how an API is used. If an API has been around for at least two releases we'll do our best to avoid breaking it.
|
||||
|
||||
Unreleased APIs may change radically. Anything that is in `develop` but not `master` is subject to change without warning.
|
||||
|
||||
### Branches
|
||||
|
||||
There are two main branches for Blockly.
|
||||
|
||||
**[master](https://github.com/google/blockly)** - This is the (mostly) stable current release of Blockly.
|
||||
|
||||
**[develop](https://github.com/google/blockly/tree/develop)** - This is where most of our work happens. Pull requests should always be made against develop. This branch will generally be usable, but may be less stable than the master branch. Once something is in develop we expect it to merge to master in the next release.
|
||||
|
||||
**other branches:** - Larger changes may have their own branches until they are good enough for people to try out. These will be developed separately until we think they are almost ready for release. These branches typically get merged into develop immediately after a release to allow extra time for testing.
|
||||
|
||||
## Issues and Milestones
|
||||
|
||||
We typically triage all bugs within 2 working days, which includes adding any appropriate labels and assigning it to a milestone. Please keep in mind, we are a small team so even feature requests that everyone agrees on may not be prioritized.
|
||||
|
||||
### Milestones
|
||||
|
||||
**Upcoming release** - The upcoming release milestone is for all bugs we plan on fixing before the next release. This typically has the form of `year_quarter_release` (such as `2019_q2_release`). Some bugs will be added to this release when they are triaged, others may be added closer to a release.
|
||||
|
||||
**Bug Bash Backlog** - These are bugs that we're still prioritizing. They haven't been added to a specific release yet, but we'll consider them for each release depending on relative priority and available time.
|
||||
|
||||
**Icebox** - These are bugs that we do not intend to spend time on. They are either too much work or minor enough that we don't expect them to ever take priority. We are still happy to accept pull requests for these bugs.
|
||||
1409
clover_blocks/www/blockly/blockly_compressed.js
Executable file
1
clover_blocks/www/blockly/blockly_compressed.js.map
Executable file
182
clover_blocks/www/blockly/blocks_compressed.js
Executable file
@@ -0,0 +1,182 @@
|
||||
// Do not edit this file; automatically generated by gulp.
|
||||
|
||||
/* eslint-disable */
|
||||
;(function(root, factory) {
|
||||
if (typeof define === 'function' && define.amd) { // AMD
|
||||
define(['./blockly_compressed.js'], factory);
|
||||
} else if (typeof exports === 'object') { // Node.js
|
||||
module.exports = factory(require('./blockly_compressed.js'));
|
||||
} else { // Browser
|
||||
root.Blockly.Blocks = factory(root.Blockly);
|
||||
}
|
||||
}(this, function(Blockly) {
|
||||
'use strict';Blockly.Blocks.colour={};Blockly.Constants={};Blockly.Constants.Colour={};Blockly.Constants.Colour.HUE=20;
|
||||
Blockly.defineBlocksWithJsonArray([{type:"colour_picker",message0:"%1",args0:[{type:"field_colour",name:"COLOUR",colour:"#ff0000"}],output:"Colour",helpUrl:"%{BKY_COLOUR_PICKER_HELPURL}",style:"colour_blocks",tooltip:"%{BKY_COLOUR_PICKER_TOOLTIP}",extensions:["parent_tooltip_when_inline"]},{type:"colour_random",message0:"%{BKY_COLOUR_RANDOM_TITLE}",output:"Colour",helpUrl:"%{BKY_COLOUR_RANDOM_HELPURL}",style:"colour_blocks",tooltip:"%{BKY_COLOUR_RANDOM_TOOLTIP}"},{type:"colour_rgb",message0:"%{BKY_COLOUR_RGB_TITLE} %{BKY_COLOUR_RGB_RED} %1 %{BKY_COLOUR_RGB_GREEN} %2 %{BKY_COLOUR_RGB_BLUE} %3",
|
||||
args0:[{type:"input_value",name:"RED",check:"Number",align:"RIGHT"},{type:"input_value",name:"GREEN",check:"Number",align:"RIGHT"},{type:"input_value",name:"BLUE",check:"Number",align:"RIGHT"}],output:"Colour",helpUrl:"%{BKY_COLOUR_RGB_HELPURL}",style:"colour_blocks",tooltip:"%{BKY_COLOUR_RGB_TOOLTIP}"},{type:"colour_blend",message0:"%{BKY_COLOUR_BLEND_TITLE} %{BKY_COLOUR_BLEND_COLOUR1} %1 %{BKY_COLOUR_BLEND_COLOUR2} %2 %{BKY_COLOUR_BLEND_RATIO} %3",args0:[{type:"input_value",name:"COLOUR1",check:"Colour",
|
||||
align:"RIGHT"},{type:"input_value",name:"COLOUR2",check:"Colour",align:"RIGHT"},{type:"input_value",name:"RATIO",check:"Number",align:"RIGHT"}],output:"Colour",helpUrl:"%{BKY_COLOUR_BLEND_HELPURL}",style:"colour_blocks",tooltip:"%{BKY_COLOUR_BLEND_TOOLTIP}"}]);Blockly.Blocks.lists={};Blockly.Constants.Lists={};Blockly.Constants.Lists.HUE=260;
|
||||
Blockly.defineBlocksWithJsonArray([{type:"lists_create_empty",message0:"%{BKY_LISTS_CREATE_EMPTY_TITLE}",output:"Array",style:"list_blocks",tooltip:"%{BKY_LISTS_CREATE_EMPTY_TOOLTIP}",helpUrl:"%{BKY_LISTS_CREATE_EMPTY_HELPURL}"},{type:"lists_repeat",message0:"%{BKY_LISTS_REPEAT_TITLE}",args0:[{type:"input_value",name:"ITEM"},{type:"input_value",name:"NUM",check:"Number"}],output:"Array",style:"list_blocks",tooltip:"%{BKY_LISTS_REPEAT_TOOLTIP}",helpUrl:"%{BKY_LISTS_REPEAT_HELPURL}"},{type:"lists_reverse",
|
||||
message0:"%{BKY_LISTS_REVERSE_MESSAGE0}",args0:[{type:"input_value",name:"LIST",check:"Array"}],output:"Array",inputsInline:!0,style:"list_blocks",tooltip:"%{BKY_LISTS_REVERSE_TOOLTIP}",helpUrl:"%{BKY_LISTS_REVERSE_HELPURL}"},{type:"lists_isEmpty",message0:"%{BKY_LISTS_ISEMPTY_TITLE}",args0:[{type:"input_value",name:"VALUE",check:["String","Array"]}],output:"Boolean",style:"list_blocks",tooltip:"%{BKY_LISTS_ISEMPTY_TOOLTIP}",helpUrl:"%{BKY_LISTS_ISEMPTY_HELPURL}"},{type:"lists_length",message0:"%{BKY_LISTS_LENGTH_TITLE}",
|
||||
args0:[{type:"input_value",name:"VALUE",check:["String","Array"]}],output:"Number",style:"list_blocks",tooltip:"%{BKY_LISTS_LENGTH_TOOLTIP}",helpUrl:"%{BKY_LISTS_LENGTH_HELPURL}"}]);
|
||||
Blockly.Blocks.lists_create_with={init:function(){this.setHelpUrl(Blockly.Msg.LISTS_CREATE_WITH_HELPURL);this.setStyle("list_blocks");this.itemCount_=3;this.updateShape_();this.setOutput(!0,"Array");this.setMutator(new Blockly.Mutator(["lists_create_with_item"]));this.setTooltip(Blockly.Msg.LISTS_CREATE_WITH_TOOLTIP)},mutationToDom:function(){var a=Blockly.utils.xml.createElement("mutation");a.setAttribute("items",this.itemCount_);return a},domToMutation:function(a){this.itemCount_=parseInt(a.getAttribute("items"),
|
||||
10);this.updateShape_()},decompose:function(a){var b=a.newBlock("lists_create_with_container");b.initSvg();for(var c=b.getInput("STACK").connection,d=0;d<this.itemCount_;d++){var e=a.newBlock("lists_create_with_item");e.initSvg();c.connect(e.previousConnection);c=e.nextConnection}return b},compose:function(a){var b=a.getInputTargetBlock("STACK");for(a=[];b;)a.push(b.valueConnection_),b=b.nextConnection&&b.nextConnection.targetBlock();for(b=0;b<this.itemCount_;b++){var c=this.getInput("ADD"+b).connection.targetConnection;
|
||||
c&&-1==a.indexOf(c)&&c.disconnect()}this.itemCount_=a.length;this.updateShape_();for(b=0;b<this.itemCount_;b++)Blockly.Mutator.reconnect(a[b],this,"ADD"+b)},saveConnections:function(a){a=a.getInputTargetBlock("STACK");for(var b=0;a;){var c=this.getInput("ADD"+b);a.valueConnection_=c&&c.connection.targetConnection;b++;a=a.nextConnection&&a.nextConnection.targetBlock()}},updateShape_:function(){this.itemCount_&&this.getInput("EMPTY")?this.removeInput("EMPTY"):this.itemCount_||this.getInput("EMPTY")||
|
||||
this.appendDummyInput("EMPTY").appendField(Blockly.Msg.LISTS_CREATE_EMPTY_TITLE);for(var a=0;a<this.itemCount_;a++)if(!this.getInput("ADD"+a)){var b=this.appendValueInput("ADD"+a).setAlign(Blockly.ALIGN_RIGHT);0==a&&b.appendField(Blockly.Msg.LISTS_CREATE_WITH_INPUT_WITH)}for(;this.getInput("ADD"+a);)this.removeInput("ADD"+a),a++}};
|
||||
Blockly.Blocks.lists_create_with_container={init:function(){this.setStyle("list_blocks");this.appendDummyInput().appendField(Blockly.Msg.LISTS_CREATE_WITH_CONTAINER_TITLE_ADD);this.appendStatementInput("STACK");this.setTooltip(Blockly.Msg.LISTS_CREATE_WITH_CONTAINER_TOOLTIP);this.contextMenu=!1}};
|
||||
Blockly.Blocks.lists_create_with_item={init:function(){this.setStyle("list_blocks");this.appendDummyInput().appendField(Blockly.Msg.LISTS_CREATE_WITH_ITEM_TITLE);this.setPreviousStatement(!0);this.setNextStatement(!0);this.setTooltip(Blockly.Msg.LISTS_CREATE_WITH_ITEM_TOOLTIP);this.contextMenu=!1}};
|
||||
Blockly.Blocks.lists_indexOf={init:function(){var a=[[Blockly.Msg.LISTS_INDEX_OF_FIRST,"FIRST"],[Blockly.Msg.LISTS_INDEX_OF_LAST,"LAST"]];this.setHelpUrl(Blockly.Msg.LISTS_INDEX_OF_HELPURL);this.setStyle("list_blocks");this.setOutput(!0,"Number");this.appendValueInput("VALUE").setCheck("Array").appendField(Blockly.Msg.LISTS_INDEX_OF_INPUT_IN_LIST);this.appendValueInput("FIND").appendField(new Blockly.FieldDropdown(a),"END");this.setInputsInline(!0);var b=this;this.setTooltip(function(){return Blockly.Msg.LISTS_INDEX_OF_TOOLTIP.replace("%1",
|
||||
b.workspace.options.oneBasedIndex?"0":"-1")})}};
|
||||
Blockly.Blocks.lists_getIndex={init:function(){var a=[[Blockly.Msg.LISTS_GET_INDEX_GET,"GET"],[Blockly.Msg.LISTS_GET_INDEX_GET_REMOVE,"GET_REMOVE"],[Blockly.Msg.LISTS_GET_INDEX_REMOVE,"REMOVE"]];this.WHERE_OPTIONS=[[Blockly.Msg.LISTS_GET_INDEX_FROM_START,"FROM_START"],[Blockly.Msg.LISTS_GET_INDEX_FROM_END,"FROM_END"],[Blockly.Msg.LISTS_GET_INDEX_FIRST,"FIRST"],[Blockly.Msg.LISTS_GET_INDEX_LAST,"LAST"],[Blockly.Msg.LISTS_GET_INDEX_RANDOM,"RANDOM"]];this.setHelpUrl(Blockly.Msg.LISTS_GET_INDEX_HELPURL);this.setStyle("list_blocks");
|
||||
a=new Blockly.FieldDropdown(a,function(a){a="REMOVE"==a;this.getSourceBlock().updateStatement_(a)});this.appendValueInput("VALUE").setCheck("Array").appendField(Blockly.Msg.LISTS_GET_INDEX_INPUT_IN_LIST);this.appendDummyInput().appendField(a,"MODE").appendField("","SPACE");this.appendDummyInput("AT");Blockly.Msg.LISTS_GET_INDEX_TAIL&&this.appendDummyInput("TAIL").appendField(Blockly.Msg.LISTS_GET_INDEX_TAIL);this.setInputsInline(!0);this.setOutput(!0);this.updateAt_(!0);var b=this;this.setTooltip(function(){var a=
|
||||
b.getFieldValue("MODE"),d=b.getFieldValue("WHERE"),e="";switch(a+" "+d){case "GET FROM_START":case "GET FROM_END":e=Blockly.Msg.LISTS_GET_INDEX_TOOLTIP_GET_FROM;break;case "GET FIRST":e=Blockly.Msg.LISTS_GET_INDEX_TOOLTIP_GET_FIRST;break;case "GET LAST":e=Blockly.Msg.LISTS_GET_INDEX_TOOLTIP_GET_LAST;break;case "GET RANDOM":e=Blockly.Msg.LISTS_GET_INDEX_TOOLTIP_GET_RANDOM;break;case "GET_REMOVE FROM_START":case "GET_REMOVE FROM_END":e=Blockly.Msg.LISTS_GET_INDEX_TOOLTIP_GET_REMOVE_FROM;break;case "GET_REMOVE FIRST":e=
|
||||
Blockly.Msg.LISTS_GET_INDEX_TOOLTIP_GET_REMOVE_FIRST;break;case "GET_REMOVE LAST":e=Blockly.Msg.LISTS_GET_INDEX_TOOLTIP_GET_REMOVE_LAST;break;case "GET_REMOVE RANDOM":e=Blockly.Msg.LISTS_GET_INDEX_TOOLTIP_GET_REMOVE_RANDOM;break;case "REMOVE FROM_START":case "REMOVE FROM_END":e=Blockly.Msg.LISTS_GET_INDEX_TOOLTIP_REMOVE_FROM;break;case "REMOVE FIRST":e=Blockly.Msg.LISTS_GET_INDEX_TOOLTIP_REMOVE_FIRST;break;case "REMOVE LAST":e=Blockly.Msg.LISTS_GET_INDEX_TOOLTIP_REMOVE_LAST;break;case "REMOVE RANDOM":e=
|
||||
Blockly.Msg.LISTS_GET_INDEX_TOOLTIP_REMOVE_RANDOM}if("FROM_START"==d||"FROM_END"==d)e+=" "+("FROM_START"==d?Blockly.Msg.LISTS_INDEX_FROM_START_TOOLTIP:Blockly.Msg.LISTS_INDEX_FROM_END_TOOLTIP).replace("%1",b.workspace.options.oneBasedIndex?"#1":"#0");return e})},mutationToDom:function(){var a=Blockly.utils.xml.createElement("mutation");a.setAttribute("statement",!this.outputConnection);var b=this.getInput("AT").type==Blockly.INPUT_VALUE;a.setAttribute("at",b);return a},domToMutation:function(a){var b=
|
||||
"true"==a.getAttribute("statement");this.updateStatement_(b);a="false"!=a.getAttribute("at");this.updateAt_(a)},updateStatement_:function(a){a!=!this.outputConnection&&(this.unplug(!0,!0),a?(this.setOutput(!1),this.setPreviousStatement(!0),this.setNextStatement(!0)):(this.setPreviousStatement(!1),this.setNextStatement(!1),this.setOutput(!0)))},updateAt_:function(a){this.removeInput("AT");this.removeInput("ORDINAL",!0);a?(this.appendValueInput("AT").setCheck("Number"),Blockly.Msg.ORDINAL_NUMBER_SUFFIX&&
|
||||
this.appendDummyInput("ORDINAL").appendField(Blockly.Msg.ORDINAL_NUMBER_SUFFIX)):this.appendDummyInput("AT");var b=new Blockly.FieldDropdown(this.WHERE_OPTIONS,function(b){var c="FROM_START"==b||"FROM_END"==b;if(c!=a){var e=this.getSourceBlock();e.updateAt_(c);e.setFieldValue(b,"WHERE");return null}});this.getInput("AT").appendField(b,"WHERE");Blockly.Msg.LISTS_GET_INDEX_TAIL&&this.moveInputBefore("TAIL",null)}};
|
||||
Blockly.Blocks.lists_setIndex={init:function(){var a=[[Blockly.Msg.LISTS_SET_INDEX_SET,"SET"],[Blockly.Msg.LISTS_SET_INDEX_INSERT,"INSERT"]];this.WHERE_OPTIONS=[[Blockly.Msg.LISTS_GET_INDEX_FROM_START,"FROM_START"],[Blockly.Msg.LISTS_GET_INDEX_FROM_END,"FROM_END"],[Blockly.Msg.LISTS_GET_INDEX_FIRST,"FIRST"],[Blockly.Msg.LISTS_GET_INDEX_LAST,"LAST"],[Blockly.Msg.LISTS_GET_INDEX_RANDOM,"RANDOM"]];this.setHelpUrl(Blockly.Msg.LISTS_SET_INDEX_HELPURL);this.setStyle("list_blocks");this.appendValueInput("LIST").setCheck("Array").appendField(Blockly.Msg.LISTS_SET_INDEX_INPUT_IN_LIST);
|
||||
this.appendDummyInput().appendField(new Blockly.FieldDropdown(a),"MODE").appendField("","SPACE");this.appendDummyInput("AT");this.appendValueInput("TO").appendField(Blockly.Msg.LISTS_SET_INDEX_INPUT_TO);this.setInputsInline(!0);this.setPreviousStatement(!0);this.setNextStatement(!0);this.setTooltip(Blockly.Msg.LISTS_SET_INDEX_TOOLTIP);this.updateAt_(!0);var b=this;this.setTooltip(function(){var a=b.getFieldValue("MODE"),d=b.getFieldValue("WHERE"),e="";switch(a+" "+d){case "SET FROM_START":case "SET FROM_END":e=
|
||||
Blockly.Msg.LISTS_SET_INDEX_TOOLTIP_SET_FROM;break;case "SET FIRST":e=Blockly.Msg.LISTS_SET_INDEX_TOOLTIP_SET_FIRST;break;case "SET LAST":e=Blockly.Msg.LISTS_SET_INDEX_TOOLTIP_SET_LAST;break;case "SET RANDOM":e=Blockly.Msg.LISTS_SET_INDEX_TOOLTIP_SET_RANDOM;break;case "INSERT FROM_START":case "INSERT FROM_END":e=Blockly.Msg.LISTS_SET_INDEX_TOOLTIP_INSERT_FROM;break;case "INSERT FIRST":e=Blockly.Msg.LISTS_SET_INDEX_TOOLTIP_INSERT_FIRST;break;case "INSERT LAST":e=Blockly.Msg.LISTS_SET_INDEX_TOOLTIP_INSERT_LAST;
|
||||
break;case "INSERT RANDOM":e=Blockly.Msg.LISTS_SET_INDEX_TOOLTIP_INSERT_RANDOM}if("FROM_START"==d||"FROM_END"==d)e+=" "+Blockly.Msg.LISTS_INDEX_FROM_START_TOOLTIP.replace("%1",b.workspace.options.oneBasedIndex?"#1":"#0");return e})},mutationToDom:function(){var a=Blockly.utils.xml.createElement("mutation"),b=this.getInput("AT").type==Blockly.INPUT_VALUE;a.setAttribute("at",b);return a},domToMutation:function(a){a="false"!=a.getAttribute("at");this.updateAt_(a)},updateAt_:function(a){this.removeInput("AT");
|
||||
this.removeInput("ORDINAL",!0);a?(this.appendValueInput("AT").setCheck("Number"),Blockly.Msg.ORDINAL_NUMBER_SUFFIX&&this.appendDummyInput("ORDINAL").appendField(Blockly.Msg.ORDINAL_NUMBER_SUFFIX)):this.appendDummyInput("AT");var b=new Blockly.FieldDropdown(this.WHERE_OPTIONS,function(b){var c="FROM_START"==b||"FROM_END"==b;if(c!=a){var e=this.getSourceBlock();e.updateAt_(c);e.setFieldValue(b,"WHERE");return null}});this.moveInputBefore("AT","TO");this.getInput("ORDINAL")&&this.moveInputBefore("ORDINAL",
|
||||
"TO");this.getInput("AT").appendField(b,"WHERE")}};
|
||||
Blockly.Blocks.lists_getSublist={init:function(){this.WHERE_OPTIONS_1=[[Blockly.Msg.LISTS_GET_SUBLIST_START_FROM_START,"FROM_START"],[Blockly.Msg.LISTS_GET_SUBLIST_START_FROM_END,"FROM_END"],[Blockly.Msg.LISTS_GET_SUBLIST_START_FIRST,"FIRST"]];this.WHERE_OPTIONS_2=[[Blockly.Msg.LISTS_GET_SUBLIST_END_FROM_START,"FROM_START"],[Blockly.Msg.LISTS_GET_SUBLIST_END_FROM_END,"FROM_END"],[Blockly.Msg.LISTS_GET_SUBLIST_END_LAST,"LAST"]];this.setHelpUrl(Blockly.Msg.LISTS_GET_SUBLIST_HELPURL);this.setStyle("list_blocks");
|
||||
this.appendValueInput("LIST").setCheck("Array").appendField(Blockly.Msg.LISTS_GET_SUBLIST_INPUT_IN_LIST);this.appendDummyInput("AT1");this.appendDummyInput("AT2");Blockly.Msg.LISTS_GET_SUBLIST_TAIL&&this.appendDummyInput("TAIL").appendField(Blockly.Msg.LISTS_GET_SUBLIST_TAIL);this.setInputsInline(!0);this.setOutput(!0,"Array");this.updateAt_(1,!0);this.updateAt_(2,!0);this.setTooltip(Blockly.Msg.LISTS_GET_SUBLIST_TOOLTIP)},mutationToDom:function(){var a=Blockly.utils.xml.createElement("mutation"),
|
||||
b=this.getInput("AT1").type==Blockly.INPUT_VALUE;a.setAttribute("at1",b);b=this.getInput("AT2").type==Blockly.INPUT_VALUE;a.setAttribute("at2",b);return a},domToMutation:function(a){var b="true"==a.getAttribute("at1");a="true"==a.getAttribute("at2");this.updateAt_(1,b);this.updateAt_(2,a)},updateAt_:function(a,b){this.removeInput("AT"+a);this.removeInput("ORDINAL"+a,!0);b?(this.appendValueInput("AT"+a).setCheck("Number"),Blockly.Msg.ORDINAL_NUMBER_SUFFIX&&this.appendDummyInput("ORDINAL"+a).appendField(Blockly.Msg.ORDINAL_NUMBER_SUFFIX)):
|
||||
this.appendDummyInput("AT"+a);var c=new Blockly.FieldDropdown(this["WHERE_OPTIONS_"+a],function(c){var e="FROM_START"==c||"FROM_END"==c;if(e!=b){var d=this.getSourceBlock();d.updateAt_(a,e);d.setFieldValue(c,"WHERE"+a);return null}});this.getInput("AT"+a).appendField(c,"WHERE"+a);1==a&&(this.moveInputBefore("AT1","AT2"),this.getInput("ORDINAL1")&&this.moveInputBefore("ORDINAL1","AT2"));Blockly.Msg.LISTS_GET_SUBLIST_TAIL&&this.moveInputBefore("TAIL",null)}};
|
||||
Blockly.Blocks.lists_sort={init:function(){this.jsonInit({message0:Blockly.Msg.LISTS_SORT_TITLE,args0:[{type:"field_dropdown",name:"TYPE",options:[[Blockly.Msg.LISTS_SORT_TYPE_NUMERIC,"NUMERIC"],[Blockly.Msg.LISTS_SORT_TYPE_TEXT,"TEXT"],[Blockly.Msg.LISTS_SORT_TYPE_IGNORECASE,"IGNORE_CASE"]]},{type:"field_dropdown",name:"DIRECTION",options:[[Blockly.Msg.LISTS_SORT_ORDER_ASCENDING,"1"],[Blockly.Msg.LISTS_SORT_ORDER_DESCENDING,"-1"]]},{type:"input_value",name:"LIST",check:"Array"}],output:"Array",style:"list_blocks",
|
||||
tooltip:Blockly.Msg.LISTS_SORT_TOOLTIP,helpUrl:Blockly.Msg.LISTS_SORT_HELPURL})}};
|
||||
Blockly.Blocks.lists_split={init:function(){var a=this,b=new Blockly.FieldDropdown([[Blockly.Msg.LISTS_SPLIT_LIST_FROM_TEXT,"SPLIT"],[Blockly.Msg.LISTS_SPLIT_TEXT_FROM_LIST,"JOIN"]],function(b){a.updateType_(b)});this.setHelpUrl(Blockly.Msg.LISTS_SPLIT_HELPURL);this.setStyle("list_blocks");this.appendValueInput("INPUT").setCheck("String").appendField(b,"MODE");this.appendValueInput("DELIM").setCheck("String").appendField(Blockly.Msg.LISTS_SPLIT_WITH_DELIMITER);this.setInputsInline(!0);this.setOutput(!0,
|
||||
"Array");this.setTooltip(function(){var b=a.getFieldValue("MODE");if("SPLIT"==b)return Blockly.Msg.LISTS_SPLIT_TOOLTIP_SPLIT;if("JOIN"==b)return Blockly.Msg.LISTS_SPLIT_TOOLTIP_JOIN;throw Error("Unknown mode: "+b);})},updateType_:function(a){if(this.getFieldValue("MODE")!=a){var b=this.getInput("INPUT").connection;b.setShadowDom(null);var c=b.targetBlock();c&&(b.disconnect(),c.isShadow()?c.dispose():this.bumpNeighbours())}"SPLIT"==a?(this.outputConnection.setCheck("Array"),this.getInput("INPUT").setCheck("String")):
|
||||
(this.outputConnection.setCheck("String"),this.getInput("INPUT").setCheck("Array"))},mutationToDom:function(){var a=Blockly.utils.xml.createElement("mutation");a.setAttribute("mode",this.getFieldValue("MODE"));return a},domToMutation:function(a){this.updateType_(a.getAttribute("mode"))}};Blockly.Blocks.logic={};Blockly.Constants.Logic={};Blockly.Constants.Logic.HUE=210;
|
||||
Blockly.defineBlocksWithJsonArray([{type:"logic_boolean",message0:"%1",args0:[{type:"field_dropdown",name:"BOOL",options:[["%{BKY_LOGIC_BOOLEAN_TRUE}","TRUE"],["%{BKY_LOGIC_BOOLEAN_FALSE}","FALSE"]]}],output:"Boolean",style:"logic_blocks",tooltip:"%{BKY_LOGIC_BOOLEAN_TOOLTIP}",helpUrl:"%{BKY_LOGIC_BOOLEAN_HELPURL}"},{type:"controls_if",message0:"%{BKY_CONTROLS_IF_MSG_IF} %1",args0:[{type:"input_value",name:"IF0",check:"Boolean"}],message1:"%{BKY_CONTROLS_IF_MSG_THEN} %1",args1:[{type:"input_statement",
|
||||
name:"DO0"}],previousStatement:null,nextStatement:null,style:"logic_blocks",helpUrl:"%{BKY_CONTROLS_IF_HELPURL}",mutator:"controls_if_mutator",extensions:["controls_if_tooltip"]},{type:"controls_ifelse",message0:"%{BKY_CONTROLS_IF_MSG_IF} %1",args0:[{type:"input_value",name:"IF0",check:"Boolean"}],message1:"%{BKY_CONTROLS_IF_MSG_THEN} %1",args1:[{type:"input_statement",name:"DO0"}],message2:"%{BKY_CONTROLS_IF_MSG_ELSE} %1",args2:[{type:"input_statement",name:"ELSE"}],previousStatement:null,nextStatement:null,
|
||||
style:"logic_blocks",tooltip:"%{BKYCONTROLS_IF_TOOLTIP_2}",helpUrl:"%{BKY_CONTROLS_IF_HELPURL}",extensions:["controls_if_tooltip"]},{type:"logic_compare",message0:"%1 %2 %3",args0:[{type:"input_value",name:"A"},{type:"field_dropdown",name:"OP",options:[["=","EQ"],["\u2260","NEQ"],["\u200f<","LT"],["\u200f\u2264","LTE"],["\u200f>","GT"],["\u200f\u2265","GTE"]]},{type:"input_value",name:"B"}],inputsInline:!0,output:"Boolean",style:"logic_blocks",helpUrl:"%{BKY_LOGIC_COMPARE_HELPURL}",extensions:["logic_compare",
|
||||
"logic_op_tooltip"]},{type:"logic_operation",message0:"%1 %2 %3",args0:[{type:"input_value",name:"A",check:"Boolean"},{type:"field_dropdown",name:"OP",options:[["%{BKY_LOGIC_OPERATION_AND}","AND"],["%{BKY_LOGIC_OPERATION_OR}","OR"]]},{type:"input_value",name:"B",check:"Boolean"}],inputsInline:!0,output:"Boolean",style:"logic_blocks",helpUrl:"%{BKY_LOGIC_OPERATION_HELPURL}",extensions:["logic_op_tooltip"]},{type:"logic_negate",message0:"%{BKY_LOGIC_NEGATE_TITLE}",args0:[{type:"input_value",name:"BOOL",
|
||||
check:"Boolean"}],output:"Boolean",style:"logic_blocks",tooltip:"%{BKY_LOGIC_NEGATE_TOOLTIP}",helpUrl:"%{BKY_LOGIC_NEGATE_HELPURL}"},{type:"logic_null",message0:"%{BKY_LOGIC_NULL}",output:null,style:"logic_blocks",tooltip:"%{BKY_LOGIC_NULL_TOOLTIP}",helpUrl:"%{BKY_LOGIC_NULL_HELPURL}"},{type:"logic_ternary",message0:"%{BKY_LOGIC_TERNARY_CONDITION} %1",args0:[{type:"input_value",name:"IF",check:"Boolean"}],message1:"%{BKY_LOGIC_TERNARY_IF_TRUE} %1",args1:[{type:"input_value",name:"THEN"}],message2:"%{BKY_LOGIC_TERNARY_IF_FALSE} %1",
|
||||
args2:[{type:"input_value",name:"ELSE"}],output:null,style:"logic_blocks",tooltip:"%{BKY_LOGIC_TERNARY_TOOLTIP}",helpUrl:"%{BKY_LOGIC_TERNARY_HELPURL}",extensions:["logic_ternary"]}]);
|
||||
Blockly.defineBlocksWithJsonArray([{type:"controls_if_if",message0:"%{BKY_CONTROLS_IF_IF_TITLE_IF}",nextStatement:null,enableContextMenu:!1,style:"logic_blocks",tooltip:"%{BKY_CONTROLS_IF_IF_TOOLTIP}"},{type:"controls_if_elseif",message0:"%{BKY_CONTROLS_IF_ELSEIF_TITLE_ELSEIF}",previousStatement:null,nextStatement:null,enableContextMenu:!1,style:"logic_blocks",tooltip:"%{BKY_CONTROLS_IF_ELSEIF_TOOLTIP}"},{type:"controls_if_else",message0:"%{BKY_CONTROLS_IF_ELSE_TITLE_ELSE}",previousStatement:null,
|
||||
enableContextMenu:!1,style:"logic_blocks",tooltip:"%{BKY_CONTROLS_IF_ELSE_TOOLTIP}"}]);Blockly.Constants.Logic.TOOLTIPS_BY_OP={EQ:"%{BKY_LOGIC_COMPARE_TOOLTIP_EQ}",NEQ:"%{BKY_LOGIC_COMPARE_TOOLTIP_NEQ}",LT:"%{BKY_LOGIC_COMPARE_TOOLTIP_LT}",LTE:"%{BKY_LOGIC_COMPARE_TOOLTIP_LTE}",GT:"%{BKY_LOGIC_COMPARE_TOOLTIP_GT}",GTE:"%{BKY_LOGIC_COMPARE_TOOLTIP_GTE}",AND:"%{BKY_LOGIC_OPERATION_TOOLTIP_AND}",OR:"%{BKY_LOGIC_OPERATION_TOOLTIP_OR}"};
|
||||
Blockly.Extensions.register("logic_op_tooltip",Blockly.Extensions.buildTooltipForDropdown("OP",Blockly.Constants.Logic.TOOLTIPS_BY_OP));
|
||||
Blockly.Constants.Logic.CONTROLS_IF_MUTATOR_MIXIN={elseifCount_:0,elseCount_:0,suppressPrefixSuffix:!0,mutationToDom:function(){if(!this.elseifCount_&&!this.elseCount_)return null;var a=Blockly.utils.xml.createElement("mutation");this.elseifCount_&&a.setAttribute("elseif",this.elseifCount_);this.elseCount_&&a.setAttribute("else",1);return a},domToMutation:function(a){this.elseifCount_=parseInt(a.getAttribute("elseif"),10)||0;this.elseCount_=parseInt(a.getAttribute("else"),10)||0;this.rebuildShape_()},
|
||||
decompose:function(a){var b=a.newBlock("controls_if_if");b.initSvg();for(var c=b.nextConnection,d=1;d<=this.elseifCount_;d++){var e=a.newBlock("controls_if_elseif");e.initSvg();c.connect(e.previousConnection);c=e.nextConnection}this.elseCount_&&(a=a.newBlock("controls_if_else"),a.initSvg(),c.connect(a.previousConnection));return b},compose:function(a){a=a.nextConnection.targetBlock();this.elseCount_=this.elseifCount_=0;for(var b=[null],c=[null],d=null;a;){switch(a.type){case "controls_if_elseif":this.elseifCount_++;
|
||||
b.push(a.valueConnection_);c.push(a.statementConnection_);break;case "controls_if_else":this.elseCount_++;d=a.statementConnection_;break;default:throw TypeError("Unknown block type: "+a.type);}a=a.nextConnection&&a.nextConnection.targetBlock()}this.updateShape_();this.reconnectChildBlocks_(b,c,d)},saveConnections:function(a){a=a.nextConnection.targetBlock();for(var b=1;a;){switch(a.type){case "controls_if_elseif":var c=this.getInput("IF"+b),d=this.getInput("DO"+b);a.valueConnection_=c&&c.connection.targetConnection;
|
||||
a.statementConnection_=d&&d.connection.targetConnection;b++;break;case "controls_if_else":d=this.getInput("ELSE");a.statementConnection_=d&&d.connection.targetConnection;break;default:throw TypeError("Unknown block type: "+a.type);}a=a.nextConnection&&a.nextConnection.targetBlock()}},rebuildShape_:function(){var a=[null],b=[null],c=null;this.getInput("ELSE")&&(c=this.getInput("ELSE").connection.targetConnection);for(var d=1;this.getInput("IF"+d);){var e=this.getInput("IF"+d),f=this.getInput("DO"+
|
||||
d);a.push(e.connection.targetConnection);b.push(f.connection.targetConnection);d++}this.updateShape_();this.reconnectChildBlocks_(a,b,c)},updateShape_:function(){this.getInput("ELSE")&&this.removeInput("ELSE");for(var a=1;this.getInput("IF"+a);)this.removeInput("IF"+a),this.removeInput("DO"+a),a++;for(a=1;a<=this.elseifCount_;a++)this.appendValueInput("IF"+a).setCheck("Boolean").appendField(Blockly.Msg.CONTROLS_IF_MSG_ELSEIF),this.appendStatementInput("DO"+a).appendField(Blockly.Msg.CONTROLS_IF_MSG_THEN);
|
||||
this.elseCount_&&this.appendStatementInput("ELSE").appendField(Blockly.Msg.CONTROLS_IF_MSG_ELSE)},reconnectChildBlocks_:function(a,b,c){for(var d=1;d<=this.elseifCount_;d++)Blockly.Mutator.reconnect(a[d],this,"IF"+d),Blockly.Mutator.reconnect(b[d],this,"DO"+d);Blockly.Mutator.reconnect(c,this,"ELSE")}};Blockly.Extensions.registerMutator("controls_if_mutator",Blockly.Constants.Logic.CONTROLS_IF_MUTATOR_MIXIN,null,["controls_if_elseif","controls_if_else"]);
|
||||
Blockly.Constants.Logic.CONTROLS_IF_TOOLTIP_EXTENSION=function(){this.setTooltip(function(){if(this.elseifCount_||this.elseCount_){if(!this.elseifCount_&&this.elseCount_)return Blockly.Msg.CONTROLS_IF_TOOLTIP_2;if(this.elseifCount_&&!this.elseCount_)return Blockly.Msg.CONTROLS_IF_TOOLTIP_3;if(this.elseifCount_&&this.elseCount_)return Blockly.Msg.CONTROLS_IF_TOOLTIP_4}else return Blockly.Msg.CONTROLS_IF_TOOLTIP_1;return""}.bind(this))};Blockly.Extensions.register("controls_if_tooltip",Blockly.Constants.Logic.CONTROLS_IF_TOOLTIP_EXTENSION);
|
||||
Blockly.Constants.Logic.LOGIC_COMPARE_ONCHANGE_MIXIN={onchange:function(a){this.prevBlocks_||(this.prevBlocks_=[null,null]);var b=this.getInputTargetBlock("A"),c=this.getInputTargetBlock("B");b&&c&&!b.outputConnection.checkType(c.outputConnection)&&(Blockly.Events.setGroup(a.group),a=this.prevBlocks_[0],a!==b&&(b.unplug(),!a||a.isDisposed()||a.isShadow()||this.getInput("A").connection.connect(a.outputConnection)),b=this.prevBlocks_[1],b!==c&&(c.unplug(),!b||b.isDisposed()||b.isShadow()||this.getInput("B").connection.connect(b.outputConnection)),
|
||||
this.bumpNeighbours(),Blockly.Events.setGroup(!1));this.prevBlocks_[0]=this.getInputTargetBlock("A");this.prevBlocks_[1]=this.getInputTargetBlock("B")}};Blockly.Constants.Logic.LOGIC_COMPARE_EXTENSION=function(){this.mixin(Blockly.Constants.Logic.LOGIC_COMPARE_ONCHANGE_MIXIN)};Blockly.Extensions.register("logic_compare",Blockly.Constants.Logic.LOGIC_COMPARE_EXTENSION);
|
||||
Blockly.Constants.Logic.LOGIC_TERNARY_ONCHANGE_MIXIN={prevParentConnection_:null,onchange:function(a){var b=this.getInputTargetBlock("THEN"),c=this.getInputTargetBlock("ELSE"),d=this.outputConnection.targetConnection;if((b||c)&&d)for(var e=0;2>e;e++){var f=1==e?b:c;f&&!f.outputConnection.checkType(d)&&(Blockly.Events.setGroup(a.group),d===this.prevParentConnection_?(this.unplug(),d.getSourceBlock().bumpNeighbours()):(f.unplug(),f.bumpNeighbours()),Blockly.Events.setGroup(!1))}this.prevParentConnection_=
|
||||
d}};Blockly.Extensions.registerMixin("logic_ternary",Blockly.Constants.Logic.LOGIC_TERNARY_ONCHANGE_MIXIN);Blockly.Blocks.loops={};Blockly.Constants.Loops={};Blockly.Constants.Loops.HUE=120;
|
||||
Blockly.defineBlocksWithJsonArray([{type:"controls_repeat_ext",message0:"%{BKY_CONTROLS_REPEAT_TITLE}",args0:[{type:"input_value",name:"TIMES",check:"Number"}],message1:"%{BKY_CONTROLS_REPEAT_INPUT_DO} %1",args1:[{type:"input_statement",name:"DO"}],previousStatement:null,nextStatement:null,style:"loop_blocks",tooltip:"%{BKY_CONTROLS_REPEAT_TOOLTIP}",helpUrl:"%{BKY_CONTROLS_REPEAT_HELPURL}"},{type:"controls_repeat",message0:"%{BKY_CONTROLS_REPEAT_TITLE}",args0:[{type:"field_number",name:"TIMES",value:10,
|
||||
min:0,precision:1}],message1:"%{BKY_CONTROLS_REPEAT_INPUT_DO} %1",args1:[{type:"input_statement",name:"DO"}],previousStatement:null,nextStatement:null,style:"loop_blocks",tooltip:"%{BKY_CONTROLS_REPEAT_TOOLTIP}",helpUrl:"%{BKY_CONTROLS_REPEAT_HELPURL}"},{type:"controls_whileUntil",message0:"%1 %2",args0:[{type:"field_dropdown",name:"MODE",options:[["%{BKY_CONTROLS_WHILEUNTIL_OPERATOR_WHILE}","WHILE"],["%{BKY_CONTROLS_WHILEUNTIL_OPERATOR_UNTIL}","UNTIL"]]},{type:"input_value",name:"BOOL",check:"Boolean"}],
|
||||
message1:"%{BKY_CONTROLS_REPEAT_INPUT_DO} %1",args1:[{type:"input_statement",name:"DO"}],previousStatement:null,nextStatement:null,style:"loop_blocks",helpUrl:"%{BKY_CONTROLS_WHILEUNTIL_HELPURL}",extensions:["controls_whileUntil_tooltip"]},{type:"controls_for",message0:"%{BKY_CONTROLS_FOR_TITLE}",args0:[{type:"field_variable",name:"VAR",variable:null},{type:"input_value",name:"FROM",check:"Number",align:"RIGHT"},{type:"input_value",name:"TO",check:"Number",align:"RIGHT"},{type:"input_value",name:"BY",
|
||||
check:"Number",align:"RIGHT"}],message1:"%{BKY_CONTROLS_REPEAT_INPUT_DO} %1",args1:[{type:"input_statement",name:"DO"}],inputsInline:!0,previousStatement:null,nextStatement:null,style:"loop_blocks",helpUrl:"%{BKY_CONTROLS_FOR_HELPURL}",extensions:["contextMenu_newGetVariableBlock","controls_for_tooltip"]},{type:"controls_forEach",message0:"%{BKY_CONTROLS_FOREACH_TITLE}",args0:[{type:"field_variable",name:"VAR",variable:null},{type:"input_value",name:"LIST",check:"Array"}],message1:"%{BKY_CONTROLS_REPEAT_INPUT_DO} %1",
|
||||
args1:[{type:"input_statement",name:"DO"}],previousStatement:null,nextStatement:null,style:"loop_blocks",helpUrl:"%{BKY_CONTROLS_FOREACH_HELPURL}",extensions:["contextMenu_newGetVariableBlock","controls_forEach_tooltip"]},{type:"controls_flow_statements",message0:"%1",args0:[{type:"field_dropdown",name:"FLOW",options:[["%{BKY_CONTROLS_FLOW_STATEMENTS_OPERATOR_BREAK}","BREAK"],["%{BKY_CONTROLS_FLOW_STATEMENTS_OPERATOR_CONTINUE}","CONTINUE"]]}],previousStatement:null,style:"loop_blocks",helpUrl:"%{BKY_CONTROLS_FLOW_STATEMENTS_HELPURL}",
|
||||
extensions:["controls_flow_tooltip","controls_flow_in_loop_check"]}]);Blockly.Constants.Loops.WHILE_UNTIL_TOOLTIPS={WHILE:"%{BKY_CONTROLS_WHILEUNTIL_TOOLTIP_WHILE}",UNTIL:"%{BKY_CONTROLS_WHILEUNTIL_TOOLTIP_UNTIL}"};Blockly.Extensions.register("controls_whileUntil_tooltip",Blockly.Extensions.buildTooltipForDropdown("MODE",Blockly.Constants.Loops.WHILE_UNTIL_TOOLTIPS));Blockly.Constants.Loops.BREAK_CONTINUE_TOOLTIPS={BREAK:"%{BKY_CONTROLS_FLOW_STATEMENTS_TOOLTIP_BREAK}",CONTINUE:"%{BKY_CONTROLS_FLOW_STATEMENTS_TOOLTIP_CONTINUE}"};
|
||||
Blockly.Extensions.register("controls_flow_tooltip",Blockly.Extensions.buildTooltipForDropdown("FLOW",Blockly.Constants.Loops.BREAK_CONTINUE_TOOLTIPS));
|
||||
Blockly.Constants.Loops.CUSTOM_CONTEXT_MENU_CREATE_VARIABLES_GET_MIXIN={customContextMenu:function(a){if(!this.isInFlyout){var b=this.getField("VAR").getVariable(),c=b.name;if(!this.isCollapsed()&&null!=c){var d={enabled:!0};d.text=Blockly.Msg.VARIABLES_SET_CREATE_GET.replace("%1",c);b=Blockly.Variables.generateVariableFieldDom(b);c=Blockly.utils.xml.createElement("block");c.setAttribute("type","variables_get");c.appendChild(b);d.callback=Blockly.ContextMenu.callbackFactory(this,c);a.push(d)}}}};
|
||||
Blockly.Extensions.registerMixin("contextMenu_newGetVariableBlock",Blockly.Constants.Loops.CUSTOM_CONTEXT_MENU_CREATE_VARIABLES_GET_MIXIN);Blockly.Extensions.register("controls_for_tooltip",Blockly.Extensions.buildTooltipWithFieldText("%{BKY_CONTROLS_FOR_TOOLTIP}","VAR"));Blockly.Extensions.register("controls_forEach_tooltip",Blockly.Extensions.buildTooltipWithFieldText("%{BKY_CONTROLS_FOREACH_TOOLTIP}","VAR"));
|
||||
Blockly.Constants.Loops.CONTROL_FLOW_IN_LOOP_CHECK_MIXIN={LOOP_TYPES:["controls_repeat","controls_repeat_ext","controls_forEach","controls_for","controls_whileUntil"],suppressPrefixSuffix:!0,getSurroundLoop:function(a){do{if(-1!=Blockly.Constants.Loops.CONTROL_FLOW_IN_LOOP_CHECK_MIXIN.LOOP_TYPES.indexOf(a.type))return a;a=a.getSurroundParent()}while(a);return null},onchange:function(a){if(this.workspace.isDragging&&!this.workspace.isDragging()&&a.type==Blockly.Events.BLOCK_MOVE&&a.blockId==this.id){var b=
|
||||
Blockly.Constants.Loops.CONTROL_FLOW_IN_LOOP_CHECK_MIXIN.getSurroundLoop(this);this.setWarningText(b?null:Blockly.Msg.CONTROLS_FLOW_STATEMENTS_WARNING);if(!this.isInFlyout){var c=Blockly.Events.getGroup();Blockly.Events.setGroup(a.group);this.setEnabled(b);Blockly.Events.setGroup(c)}}}};Blockly.Extensions.registerMixin("controls_flow_in_loop_check",Blockly.Constants.Loops.CONTROL_FLOW_IN_LOOP_CHECK_MIXIN);Blockly.Blocks.math={};Blockly.Constants.Math={};Blockly.Constants.Math.HUE=230;
|
||||
Blockly.defineBlocksWithJsonArray([{type:"math_number",message0:"%1",args0:[{type:"field_number",name:"NUM",value:0}],output:"Number",helpUrl:"%{BKY_MATH_NUMBER_HELPURL}",style:"math_blocks",tooltip:"%{BKY_MATH_NUMBER_TOOLTIP}",extensions:["parent_tooltip_when_inline"]},{type:"math_arithmetic",message0:"%1 %2 %3",args0:[{type:"input_value",name:"A",check:"Number"},{type:"field_dropdown",name:"OP",options:[["%{BKY_MATH_ADDITION_SYMBOL}","ADD"],["%{BKY_MATH_SUBTRACTION_SYMBOL}","MINUS"],["%{BKY_MATH_MULTIPLICATION_SYMBOL}",
|
||||
"MULTIPLY"],["%{BKY_MATH_DIVISION_SYMBOL}","DIVIDE"],["%{BKY_MATH_POWER_SYMBOL}","POWER"]]},{type:"input_value",name:"B",check:"Number"}],inputsInline:!0,output:"Number",style:"math_blocks",helpUrl:"%{BKY_MATH_ARITHMETIC_HELPURL}",extensions:["math_op_tooltip"]},{type:"math_single",message0:"%1 %2",args0:[{type:"field_dropdown",name:"OP",options:[["%{BKY_MATH_SINGLE_OP_ROOT}","ROOT"],["%{BKY_MATH_SINGLE_OP_ABSOLUTE}","ABS"],["-","NEG"],["ln","LN"],["log10","LOG10"],["e^","EXP"],["10^","POW10"]]},
|
||||
{type:"input_value",name:"NUM",check:"Number"}],output:"Number",style:"math_blocks",helpUrl:"%{BKY_MATH_SINGLE_HELPURL}",extensions:["math_op_tooltip"]},{type:"math_trig",message0:"%1 %2",args0:[{type:"field_dropdown",name:"OP",options:[["%{BKY_MATH_TRIG_SIN}","SIN"],["%{BKY_MATH_TRIG_COS}","COS"],["%{BKY_MATH_TRIG_TAN}","TAN"],["%{BKY_MATH_TRIG_ASIN}","ASIN"],["%{BKY_MATH_TRIG_ACOS}","ACOS"],["%{BKY_MATH_TRIG_ATAN}","ATAN"]]},{type:"input_value",name:"NUM",check:"Number"}],output:"Number",style:"math_blocks",
|
||||
helpUrl:"%{BKY_MATH_TRIG_HELPURL}",extensions:["math_op_tooltip"]},{type:"math_constant",message0:"%1",args0:[{type:"field_dropdown",name:"CONSTANT",options:[["\u03c0","PI"],["e","E"],["\u03c6","GOLDEN_RATIO"],["sqrt(2)","SQRT2"],["sqrt(\u00bd)","SQRT1_2"],["\u221e","INFINITY"]]}],output:"Number",style:"math_blocks",tooltip:"%{BKY_MATH_CONSTANT_TOOLTIP}",helpUrl:"%{BKY_MATH_CONSTANT_HELPURL}"},{type:"math_number_property",message0:"%1 %2",args0:[{type:"input_value",name:"NUMBER_TO_CHECK",check:"Number"},
|
||||
{type:"field_dropdown",name:"PROPERTY",options:[["%{BKY_MATH_IS_EVEN}","EVEN"],["%{BKY_MATH_IS_ODD}","ODD"],["%{BKY_MATH_IS_PRIME}","PRIME"],["%{BKY_MATH_IS_WHOLE}","WHOLE"],["%{BKY_MATH_IS_POSITIVE}","POSITIVE"],["%{BKY_MATH_IS_NEGATIVE}","NEGATIVE"],["%{BKY_MATH_IS_DIVISIBLE_BY}","DIVISIBLE_BY"]]}],inputsInline:!0,output:"Boolean",style:"math_blocks",tooltip:"%{BKY_MATH_IS_TOOLTIP}",mutator:"math_is_divisibleby_mutator"},{type:"math_change",message0:"%{BKY_MATH_CHANGE_TITLE}",args0:[{type:"field_variable",
|
||||
name:"VAR",variable:"%{BKY_MATH_CHANGE_TITLE_ITEM}"},{type:"input_value",name:"DELTA",check:"Number"}],previousStatement:null,nextStatement:null,style:"variable_blocks",helpUrl:"%{BKY_MATH_CHANGE_HELPURL}",extensions:["math_change_tooltip"]},{type:"math_round",message0:"%1 %2",args0:[{type:"field_dropdown",name:"OP",options:[["%{BKY_MATH_ROUND_OPERATOR_ROUND}","ROUND"],["%{BKY_MATH_ROUND_OPERATOR_ROUNDUP}","ROUNDUP"],["%{BKY_MATH_ROUND_OPERATOR_ROUNDDOWN}","ROUNDDOWN"]]},{type:"input_value",name:"NUM",
|
||||
check:"Number"}],output:"Number",style:"math_blocks",helpUrl:"%{BKY_MATH_ROUND_HELPURL}",tooltip:"%{BKY_MATH_ROUND_TOOLTIP}"},{type:"math_on_list",message0:"%1 %2",args0:[{type:"field_dropdown",name:"OP",options:[["%{BKY_MATH_ONLIST_OPERATOR_SUM}","SUM"],["%{BKY_MATH_ONLIST_OPERATOR_MIN}","MIN"],["%{BKY_MATH_ONLIST_OPERATOR_MAX}","MAX"],["%{BKY_MATH_ONLIST_OPERATOR_AVERAGE}","AVERAGE"],["%{BKY_MATH_ONLIST_OPERATOR_MEDIAN}","MEDIAN"],["%{BKY_MATH_ONLIST_OPERATOR_MODE}","MODE"],["%{BKY_MATH_ONLIST_OPERATOR_STD_DEV}",
|
||||
"STD_DEV"],["%{BKY_MATH_ONLIST_OPERATOR_RANDOM}","RANDOM"]]},{type:"input_value",name:"LIST",check:"Array"}],output:"Number",style:"math_blocks",helpUrl:"%{BKY_MATH_ONLIST_HELPURL}",mutator:"math_modes_of_list_mutator",extensions:["math_op_tooltip"]},{type:"math_modulo",message0:"%{BKY_MATH_MODULO_TITLE}",args0:[{type:"input_value",name:"DIVIDEND",check:"Number"},{type:"input_value",name:"DIVISOR",check:"Number"}],inputsInline:!0,output:"Number",style:"math_blocks",tooltip:"%{BKY_MATH_MODULO_TOOLTIP}",
|
||||
helpUrl:"%{BKY_MATH_MODULO_HELPURL}"},{type:"math_constrain",message0:"%{BKY_MATH_CONSTRAIN_TITLE}",args0:[{type:"input_value",name:"VALUE",check:"Number"},{type:"input_value",name:"LOW",check:"Number"},{type:"input_value",name:"HIGH",check:"Number"}],inputsInline:!0,output:"Number",style:"math_blocks",tooltip:"%{BKY_MATH_CONSTRAIN_TOOLTIP}",helpUrl:"%{BKY_MATH_CONSTRAIN_HELPURL}"},{type:"math_random_int",message0:"%{BKY_MATH_RANDOM_INT_TITLE}",args0:[{type:"input_value",name:"FROM",check:"Number"},
|
||||
{type:"input_value",name:"TO",check:"Number"}],inputsInline:!0,output:"Number",style:"math_blocks",tooltip:"%{BKY_MATH_RANDOM_INT_TOOLTIP}",helpUrl:"%{BKY_MATH_RANDOM_INT_HELPURL}"},{type:"math_random_float",message0:"%{BKY_MATH_RANDOM_FLOAT_TITLE_RANDOM}",output:"Number",style:"math_blocks",tooltip:"%{BKY_MATH_RANDOM_FLOAT_TOOLTIP}",helpUrl:"%{BKY_MATH_RANDOM_FLOAT_HELPURL}"},{type:"math_atan2",message0:"%{BKY_MATH_ATAN2_TITLE}",args0:[{type:"input_value",name:"X",check:"Number"},{type:"input_value",
|
||||
name:"Y",check:"Number"}],inputsInline:!0,output:"Number",style:"math_blocks",tooltip:"%{BKY_MATH_ATAN2_TOOLTIP}",helpUrl:"%{BKY_MATH_ATAN2_HELPURL}"}]);
|
||||
Blockly.Constants.Math.TOOLTIPS_BY_OP={ADD:"%{BKY_MATH_ARITHMETIC_TOOLTIP_ADD}",MINUS:"%{BKY_MATH_ARITHMETIC_TOOLTIP_MINUS}",MULTIPLY:"%{BKY_MATH_ARITHMETIC_TOOLTIP_MULTIPLY}",DIVIDE:"%{BKY_MATH_ARITHMETIC_TOOLTIP_DIVIDE}",POWER:"%{BKY_MATH_ARITHMETIC_TOOLTIP_POWER}",ROOT:"%{BKY_MATH_SINGLE_TOOLTIP_ROOT}",ABS:"%{BKY_MATH_SINGLE_TOOLTIP_ABS}",NEG:"%{BKY_MATH_SINGLE_TOOLTIP_NEG}",LN:"%{BKY_MATH_SINGLE_TOOLTIP_LN}",LOG10:"%{BKY_MATH_SINGLE_TOOLTIP_LOG10}",EXP:"%{BKY_MATH_SINGLE_TOOLTIP_EXP}",POW10:"%{BKY_MATH_SINGLE_TOOLTIP_POW10}",
|
||||
SIN:"%{BKY_MATH_TRIG_TOOLTIP_SIN}",COS:"%{BKY_MATH_TRIG_TOOLTIP_COS}",TAN:"%{BKY_MATH_TRIG_TOOLTIP_TAN}",ASIN:"%{BKY_MATH_TRIG_TOOLTIP_ASIN}",ACOS:"%{BKY_MATH_TRIG_TOOLTIP_ACOS}",ATAN:"%{BKY_MATH_TRIG_TOOLTIP_ATAN}",SUM:"%{BKY_MATH_ONLIST_TOOLTIP_SUM}",MIN:"%{BKY_MATH_ONLIST_TOOLTIP_MIN}",MAX:"%{BKY_MATH_ONLIST_TOOLTIP_MAX}",AVERAGE:"%{BKY_MATH_ONLIST_TOOLTIP_AVERAGE}",MEDIAN:"%{BKY_MATH_ONLIST_TOOLTIP_MEDIAN}",MODE:"%{BKY_MATH_ONLIST_TOOLTIP_MODE}",STD_DEV:"%{BKY_MATH_ONLIST_TOOLTIP_STD_DEV}",RANDOM:"%{BKY_MATH_ONLIST_TOOLTIP_RANDOM}"};
|
||||
Blockly.Extensions.register("math_op_tooltip",Blockly.Extensions.buildTooltipForDropdown("OP",Blockly.Constants.Math.TOOLTIPS_BY_OP));
|
||||
Blockly.Constants.Math.IS_DIVISIBLEBY_MUTATOR_MIXIN={mutationToDom:function(){var a=Blockly.utils.xml.createElement("mutation"),b="DIVISIBLE_BY"==this.getFieldValue("PROPERTY");a.setAttribute("divisor_input",b);return a},domToMutation:function(a){a="true"==a.getAttribute("divisor_input");this.updateShape_(a)},updateShape_:function(a){var b=this.getInput("DIVISOR");a?b||this.appendValueInput("DIVISOR").setCheck("Number"):b&&this.removeInput("DIVISOR")}};
|
||||
Blockly.Constants.Math.IS_DIVISIBLE_MUTATOR_EXTENSION=function(){this.getField("PROPERTY").setValidator(function(a){a="DIVISIBLE_BY"==a;this.getSourceBlock().updateShape_(a)})};Blockly.Extensions.registerMutator("math_is_divisibleby_mutator",Blockly.Constants.Math.IS_DIVISIBLEBY_MUTATOR_MIXIN,Blockly.Constants.Math.IS_DIVISIBLE_MUTATOR_EXTENSION);Blockly.Extensions.register("math_change_tooltip",Blockly.Extensions.buildTooltipWithFieldText("%{BKY_MATH_CHANGE_TOOLTIP}","VAR"));
|
||||
Blockly.Constants.Math.LIST_MODES_MUTATOR_MIXIN={updateType_:function(a){"MODE"==a?this.outputConnection.setCheck("Array"):this.outputConnection.setCheck("Number")},mutationToDom:function(){var a=Blockly.utils.xml.createElement("mutation");a.setAttribute("op",this.getFieldValue("OP"));return a},domToMutation:function(a){this.updateType_(a.getAttribute("op"))}};Blockly.Constants.Math.LIST_MODES_MUTATOR_EXTENSION=function(){this.getField("OP").setValidator(function(a){this.updateType_(a)}.bind(this))};
|
||||
Blockly.Extensions.registerMutator("math_modes_of_list_mutator",Blockly.Constants.Math.LIST_MODES_MUTATOR_MIXIN,Blockly.Constants.Math.LIST_MODES_MUTATOR_EXTENSION);Blockly.Blocks.procedures={};
|
||||
Blockly.Blocks.procedures_defnoreturn={init:function(){var a=new Blockly.FieldTextInput("",Blockly.Procedures.rename);a.setSpellcheck(!1);this.appendDummyInput().appendField(Blockly.Msg.PROCEDURES_DEFNORETURN_TITLE).appendField(a,"NAME").appendField("","PARAMS");this.setMutator(new Blockly.Mutator(["procedures_mutatorarg"]));(this.workspace.options.comments||this.workspace.options.parentWorkspace&&this.workspace.options.parentWorkspace.options.comments)&&Blockly.Msg.PROCEDURES_DEFNORETURN_COMMENT&&this.setCommentText(Blockly.Msg.PROCEDURES_DEFNORETURN_COMMENT);
|
||||
this.setStyle("procedure_blocks");this.setTooltip(Blockly.Msg.PROCEDURES_DEFNORETURN_TOOLTIP);this.setHelpUrl(Blockly.Msg.PROCEDURES_DEFNORETURN_HELPURL);this.arguments_=[];this.argumentVarModels_=[];this.setStatements_(!0);this.statementConnection_=null},setStatements_:function(a){this.hasStatements_!==a&&(a?(this.appendStatementInput("STACK").appendField(Blockly.Msg.PROCEDURES_DEFNORETURN_DO),this.getInput("RETURN")&&this.moveInputBefore("STACK","RETURN")):this.removeInput("STACK",!0),this.hasStatements_=
|
||||
a)},updateParams_:function(){var a="";this.arguments_.length&&(a=Blockly.Msg.PROCEDURES_BEFORE_PARAMS+" "+this.arguments_.join(", "));Blockly.Events.disable();try{this.setFieldValue(a,"PARAMS")}finally{Blockly.Events.enable()}},mutationToDom:function(a){var b=Blockly.utils.xml.createElement("mutation");a&&b.setAttribute("name",this.getFieldValue("NAME"));for(var c=0;c<this.argumentVarModels_.length;c++){var d=Blockly.utils.xml.createElement("arg"),e=this.argumentVarModels_[c];d.setAttribute("name",
|
||||
e.name);d.setAttribute("varid",e.getId());a&&this.paramIds_&&d.setAttribute("paramId",this.paramIds_[c]);b.appendChild(d)}this.hasStatements_||b.setAttribute("statements","false");return b},domToMutation:function(a){this.arguments_=[];this.argumentVarModels_=[];for(var b=0,c;c=a.childNodes[b];b++)if("arg"==c.nodeName.toLowerCase()){var d=c.getAttribute("name");c=c.getAttribute("varid")||c.getAttribute("varId");this.arguments_.push(d);c=Blockly.Variables.getOrCreateVariablePackage(this.workspace,c,
|
||||
d,"");null!=c?this.argumentVarModels_.push(c):console.log("Failed to create a variable with name "+d+", ignoring.")}this.updateParams_();Blockly.Procedures.mutateCallers(this);this.setStatements_("false"!==a.getAttribute("statements"))},decompose:function(a){var b=Blockly.utils.xml.createElement("block");b.setAttribute("type","procedures_mutatorcontainer");var c=Blockly.utils.xml.createElement("statement");c.setAttribute("name","STACK");b.appendChild(c);for(var d=0;d<this.arguments_.length;d++){var e=
|
||||
Blockly.utils.xml.createElement("block");e.setAttribute("type","procedures_mutatorarg");var f=Blockly.utils.xml.createElement("field");f.setAttribute("name","NAME");var g=Blockly.utils.xml.createTextNode(this.arguments_[d]);f.appendChild(g);e.appendChild(f);f=Blockly.utils.xml.createElement("next");e.appendChild(f);c.appendChild(e);c=f}a=Blockly.Xml.domToBlock(b,a);"procedures_defreturn"==this.type?a.setFieldValue(this.hasStatements_,"STATEMENTS"):a.removeInput("STATEMENT_INPUT");Blockly.Procedures.mutateCallers(this);
|
||||
return a},compose:function(a){this.arguments_=[];this.paramIds_=[];this.argumentVarModels_=[];for(var b=a.getInputTargetBlock("STACK");b;){var c=b.getFieldValue("NAME");this.arguments_.push(c);c=this.workspace.getVariable(c,"");this.argumentVarModels_.push(c);this.paramIds_.push(b.id);b=b.nextConnection&&b.nextConnection.targetBlock()}this.updateParams_();Blockly.Procedures.mutateCallers(this);a=a.getFieldValue("STATEMENTS");if(null!==a&&(a="TRUE"==a,this.hasStatements_!=a))if(a)this.setStatements_(!0),
|
||||
Blockly.Mutator.reconnect(this.statementConnection_,this,"STACK"),this.statementConnection_=null;else{a=this.getInput("STACK").connection;if(this.statementConnection_=a.targetConnection)a=a.targetBlock(),a.unplug(),a.bumpNeighbours();this.setStatements_(!1)}},getProcedureDef:function(){return[this.getFieldValue("NAME"),this.arguments_,!1]},getVars:function(){return this.arguments_},getVarModels:function(){return this.argumentVarModels_},renameVarById:function(a,b){var c=this.workspace.getVariableById(a);
|
||||
if(""==c.type){c=c.name;b=this.workspace.getVariableById(b);for(var d=!1,e=0;e<this.argumentVarModels_.length;e++)this.argumentVarModels_[e].getId()==a&&(this.arguments_[e]=b.name,this.argumentVarModels_[e]=b,d=!0);d&&(this.displayRenamedVar_(c,b.name),Blockly.Procedures.mutateCallers(this))}},updateVarName:function(a){for(var b=a.name,c=!1,d=0;d<this.argumentVarModels_.length;d++)if(this.argumentVarModels_[d].getId()==a.getId()){var e=this.arguments_[d];this.arguments_[d]=b;c=!0}c&&(this.displayRenamedVar_(e,
|
||||
b),Blockly.Procedures.mutateCallers(this))},displayRenamedVar_:function(a,b){this.updateParams_();if(this.mutator&&this.mutator.isVisible())for(var c=this.mutator.workspace_.getAllBlocks(!1),d=0,e;e=c[d];d++)"procedures_mutatorarg"==e.type&&Blockly.Names.equals(a,e.getFieldValue("NAME"))&&e.setFieldValue(b,"NAME")},customContextMenu:function(a){if(!this.isInFlyout){var b={enabled:!0},c=this.getFieldValue("NAME");b.text=Blockly.Msg.PROCEDURES_CREATE_DO.replace("%1",c);var d=Blockly.utils.xml.createElement("mutation");
|
||||
d.setAttribute("name",c);for(c=0;c<this.arguments_.length;c++){var e=Blockly.utils.xml.createElement("arg");e.setAttribute("name",this.arguments_[c]);d.appendChild(e)}c=Blockly.utils.xml.createElement("block");c.setAttribute("type",this.callType_);c.appendChild(d);b.callback=Blockly.ContextMenu.callbackFactory(this,c);a.push(b);if(!this.isCollapsed())for(c=0;c<this.argumentVarModels_.length;c++)b={enabled:!0},d=this.argumentVarModels_[c],b.text=Blockly.Msg.VARIABLES_SET_CREATE_GET.replace("%1",d.name),
|
||||
d=Blockly.Variables.generateVariableFieldDom(d),e=Blockly.utils.xml.createElement("block"),e.setAttribute("type","variables_get"),e.appendChild(d),b.callback=Blockly.ContextMenu.callbackFactory(this,e),a.push(b)}},callType_:"procedures_callnoreturn"};
|
||||
Blockly.Blocks.procedures_defreturn={init:function(){var a=new Blockly.FieldTextInput("",Blockly.Procedures.rename);a.setSpellcheck(!1);this.appendDummyInput().appendField(Blockly.Msg.PROCEDURES_DEFRETURN_TITLE).appendField(a,"NAME").appendField("","PARAMS");this.appendValueInput("RETURN").setAlign(Blockly.ALIGN_RIGHT).appendField(Blockly.Msg.PROCEDURES_DEFRETURN_RETURN);this.setMutator(new Blockly.Mutator(["procedures_mutatorarg"]));(this.workspace.options.comments||this.workspace.options.parentWorkspace&&
|
||||
this.workspace.options.parentWorkspace.options.comments)&&Blockly.Msg.PROCEDURES_DEFRETURN_COMMENT&&this.setCommentText(Blockly.Msg.PROCEDURES_DEFRETURN_COMMENT);this.setStyle("procedure_blocks");this.setTooltip(Blockly.Msg.PROCEDURES_DEFRETURN_TOOLTIP);this.setHelpUrl(Blockly.Msg.PROCEDURES_DEFRETURN_HELPURL);this.arguments_=[];this.argumentVarModels_=[];this.setStatements_(!0);this.statementConnection_=null},setStatements_:Blockly.Blocks.procedures_defnoreturn.setStatements_,updateParams_:Blockly.Blocks.procedures_defnoreturn.updateParams_,
|
||||
mutationToDom:Blockly.Blocks.procedures_defnoreturn.mutationToDom,domToMutation:Blockly.Blocks.procedures_defnoreturn.domToMutation,decompose:Blockly.Blocks.procedures_defnoreturn.decompose,compose:Blockly.Blocks.procedures_defnoreturn.compose,getProcedureDef:function(){return[this.getFieldValue("NAME"),this.arguments_,!0]},getVars:Blockly.Blocks.procedures_defnoreturn.getVars,getVarModels:Blockly.Blocks.procedures_defnoreturn.getVarModels,renameVarById:Blockly.Blocks.procedures_defnoreturn.renameVarById,
|
||||
updateVarName:Blockly.Blocks.procedures_defnoreturn.updateVarName,displayRenamedVar_:Blockly.Blocks.procedures_defnoreturn.displayRenamedVar_,customContextMenu:Blockly.Blocks.procedures_defnoreturn.customContextMenu,callType_:"procedures_callreturn"};
|
||||
Blockly.Blocks.procedures_mutatorcontainer={init:function(){this.appendDummyInput().appendField(Blockly.Msg.PROCEDURES_MUTATORCONTAINER_TITLE);this.appendStatementInput("STACK");this.appendDummyInput("STATEMENT_INPUT").appendField(Blockly.Msg.PROCEDURES_ALLOW_STATEMENTS).appendField(new Blockly.FieldCheckbox("TRUE"),"STATEMENTS");this.setStyle("procedure_blocks");this.setTooltip(Blockly.Msg.PROCEDURES_MUTATORCONTAINER_TOOLTIP);this.contextMenu=!1}};
|
||||
Blockly.Blocks.procedures_mutatorarg={init:function(){var a=new Blockly.FieldTextInput(Blockly.Procedures.DEFAULT_ARG,this.validator_);a.oldShowEditorFn_=a.showEditor_;a.showEditor_=function(){this.createdVariables_=[];this.oldShowEditorFn_()};this.appendDummyInput().appendField(Blockly.Msg.PROCEDURES_MUTATORARG_TITLE).appendField(a,"NAME");this.setPreviousStatement(!0);this.setNextStatement(!0);this.setStyle("procedure_blocks");this.setTooltip(Blockly.Msg.PROCEDURES_MUTATORARG_TOOLTIP);this.contextMenu=
|
||||
!1;a.onFinishEditing_=this.deleteIntermediateVars_;a.createdVariables_=[];a.onFinishEditing_("x")},validator_:function(a){var b=this.getSourceBlock(),c=Blockly.Mutator.findParentWs(b.workspace);a=a.replace(/[\s\xa0]+/g," ").replace(/^ | $/g,"");if(!a)return null;for(var d=(b.workspace.targetWorkspace||b.workspace).getAllBlocks(!1),e=a.toLowerCase(),f=0;f<d.length;f++)if(d[f].id!=this.getSourceBlock().id){var g=d[f].getFieldValue("NAME");if(g&&g.toLowerCase()==e)return null}if(b.isInFlyout)return a;
|
||||
(b=c.getVariable(a,""))&&b.name!=a&&c.renameVariableById(b.getId(),a);b||(b=c.createVariable(a,""))&&this.createdVariables_&&this.createdVariables_.push(b);return a},deleteIntermediateVars_:function(a){var b=Blockly.Mutator.findParentWs(this.getSourceBlock().workspace);if(b)for(var c=0;c<this.createdVariables_.length;c++){var d=this.createdVariables_[c];d.name!=a&&b.deleteVariableById(d.getId())}}};
|
||||
Blockly.Blocks.procedures_callnoreturn={init:function(){this.appendDummyInput("TOPROW").appendField(this.id,"NAME");this.setPreviousStatement(!0);this.setNextStatement(!0);this.setStyle("procedure_blocks");this.setHelpUrl(Blockly.Msg.PROCEDURES_CALLNORETURN_HELPURL);this.arguments_=[];this.argumentVarModels_=[];this.quarkConnections_={};this.quarkIds_=null;this.previousEnabledState_=!0},getProcedureCall:function(){return this.getFieldValue("NAME")},renameProcedure:function(a,b){Blockly.Names.equals(a,
|
||||
this.getProcedureCall())&&(this.setFieldValue(b,"NAME"),this.setTooltip((this.outputConnection?Blockly.Msg.PROCEDURES_CALLRETURN_TOOLTIP:Blockly.Msg.PROCEDURES_CALLNORETURN_TOOLTIP).replace("%1",b)))},setProcedureParameters_:function(a,b){var c=Blockly.Procedures.getDefinition(this.getProcedureCall(),this.workspace),d=c&&c.mutator&&c.mutator.isVisible();d||(this.quarkConnections_={},this.quarkIds_=null);if(b)if(a.join("\n")==this.arguments_.join("\n"))this.quarkIds_=b;else{if(b.length!=a.length)throw RangeError("paramNames and paramIds must be the same length.");
|
||||
this.setCollapsed(!1);this.quarkIds_||(this.quarkConnections_={},this.quarkIds_=[]);c=this.rendered;this.rendered=!1;for(var e=0;e<this.arguments_.length;e++){var f=this.getInput("ARG"+e);f&&(f=f.connection.targetConnection,this.quarkConnections_[this.quarkIds_[e]]=f,d&&f&&-1==b.indexOf(this.quarkIds_[e])&&(f.disconnect(),f.getSourceBlock().bumpNeighbours()))}this.arguments_=[].concat(a);this.argumentVarModels_=[];for(e=0;e<this.arguments_.length;e++)a=Blockly.Variables.getOrCreateVariablePackage(this.workspace,
|
||||
null,this.arguments_[e],""),this.argumentVarModels_.push(a);this.updateShape_();if(this.quarkIds_=b)for(e=0;e<this.arguments_.length;e++)b=this.quarkIds_[e],b in this.quarkConnections_&&(f=this.quarkConnections_[b],Blockly.Mutator.reconnect(f,this,"ARG"+e)||delete this.quarkConnections_[b]);(this.rendered=c)&&this.render()}},updateShape_:function(){for(var a=0;a<this.arguments_.length;a++){var b=this.getField("ARGNAME"+a);if(b){Blockly.Events.disable();try{b.setValue(this.arguments_[a])}finally{Blockly.Events.enable()}}else b=
|
||||
new Blockly.FieldLabel(this.arguments_[a]),this.appendValueInput("ARG"+a).setAlign(Blockly.ALIGN_RIGHT).appendField(b,"ARGNAME"+a).init()}for(;this.getInput("ARG"+a);)this.removeInput("ARG"+a),a++;if(a=this.getInput("TOPROW"))this.arguments_.length?this.getField("WITH")||(a.appendField(Blockly.Msg.PROCEDURES_CALL_BEFORE_PARAMS,"WITH"),a.init()):this.getField("WITH")&&a.removeField("WITH")},mutationToDom:function(){var a=Blockly.utils.xml.createElement("mutation");a.setAttribute("name",this.getProcedureCall());
|
||||
for(var b=0;b<this.arguments_.length;b++){var c=Blockly.utils.xml.createElement("arg");c.setAttribute("name",this.arguments_[b]);a.appendChild(c)}return a},domToMutation:function(a){var b=a.getAttribute("name");this.renameProcedure(this.getProcedureCall(),b);b=[];for(var c=[],d=0,e;e=a.childNodes[d];d++)"arg"==e.nodeName.toLowerCase()&&(b.push(e.getAttribute("name")),c.push(e.getAttribute("paramId")));this.setProcedureParameters_(b,c)},getVars:function(){return this.arguments_},getVarModels:function(){return this.argumentVarModels_},
|
||||
onchange:function(a){if(this.workspace&&!this.workspace.isFlyout&&a.recordUndo)if(a.type==Blockly.Events.BLOCK_CREATE&&-1!=a.ids.indexOf(this.id)){var b=this.getProcedureCall();b=Blockly.Procedures.getDefinition(b,this.workspace);!b||b.type==this.defType_&&JSON.stringify(b.getVars())==JSON.stringify(this.arguments_)||(b=null);if(!b){Blockly.Events.setGroup(a.group);a=Blockly.utils.xml.createElement("xml");b=Blockly.utils.xml.createElement("block");b.setAttribute("type",this.defType_);var c=this.getRelativeToSurfaceXY(),
|
||||
d=c.y+2*Blockly.SNAP_RADIUS;b.setAttribute("x",c.x+Blockly.SNAP_RADIUS*(this.RTL?-1:1));b.setAttribute("y",d);c=this.mutationToDom();b.appendChild(c);c=Blockly.utils.xml.createElement("field");c.setAttribute("name","NAME");c.appendChild(Blockly.utils.xml.createTextNode(this.getProcedureCall()));b.appendChild(c);a.appendChild(b);Blockly.Xml.domToWorkspace(a,this.workspace);Blockly.Events.setGroup(!1)}}else a.type==Blockly.Events.BLOCK_DELETE?(b=this.getProcedureCall(),b=Blockly.Procedures.getDefinition(b,
|
||||
this.workspace),b||(Blockly.Events.setGroup(a.group),this.dispose(!0),Blockly.Events.setGroup(!1))):a.type==Blockly.Events.CHANGE&&"disabled"==a.element&&(b=this.getProcedureCall(),(b=Blockly.Procedures.getDefinition(b,this.workspace))&&b.id==a.blockId&&((b=Blockly.Events.getGroup())&&console.log("Saw an existing group while responding to a definition change"),Blockly.Events.setGroup(a.group),a.newValue?(this.previousEnabledState_=this.isEnabled(),this.setEnabled(!1)):this.setEnabled(this.previousEnabledState_),
|
||||
Blockly.Events.setGroup(b)))},customContextMenu:function(a){if(this.workspace.isMovable()){var b={enabled:!0};b.text=Blockly.Msg.PROCEDURES_HIGHLIGHT_DEF;var c=this.getProcedureCall(),d=this.workspace;b.callback=function(){var a=Blockly.Procedures.getDefinition(c,d);a&&(d.centerOnBlock(a.id),a.select())};a.push(b)}},defType_:"procedures_defnoreturn"};
|
||||
Blockly.Blocks.procedures_callreturn={init:function(){this.appendDummyInput("TOPROW").appendField("","NAME");this.setOutput(!0);this.setStyle("procedure_blocks");this.setHelpUrl(Blockly.Msg.PROCEDURES_CALLRETURN_HELPURL);this.arguments_=[];this.quarkConnections_={};this.quarkIds_=null;this.previousEnabledState_=!0},getProcedureCall:Blockly.Blocks.procedures_callnoreturn.getProcedureCall,renameProcedure:Blockly.Blocks.procedures_callnoreturn.renameProcedure,setProcedureParameters_:Blockly.Blocks.procedures_callnoreturn.setProcedureParameters_,
|
||||
updateShape_:Blockly.Blocks.procedures_callnoreturn.updateShape_,mutationToDom:Blockly.Blocks.procedures_callnoreturn.mutationToDom,domToMutation:Blockly.Blocks.procedures_callnoreturn.domToMutation,getVars:Blockly.Blocks.procedures_callnoreturn.getVars,getVarModels:Blockly.Blocks.procedures_callnoreturn.getVarModels,onchange:Blockly.Blocks.procedures_callnoreturn.onchange,customContextMenu:Blockly.Blocks.procedures_callnoreturn.customContextMenu,defType_:"procedures_defreturn"};
|
||||
Blockly.Blocks.procedures_ifreturn={init:function(){this.appendValueInput("CONDITION").setCheck("Boolean").appendField(Blockly.Msg.CONTROLS_IF_MSG_IF);this.appendValueInput("VALUE").appendField(Blockly.Msg.PROCEDURES_DEFRETURN_RETURN);this.setInputsInline(!0);this.setPreviousStatement(!0);this.setNextStatement(!0);this.setStyle("procedure_blocks");this.setTooltip(Blockly.Msg.PROCEDURES_IFRETURN_TOOLTIP);this.setHelpUrl(Blockly.Msg.PROCEDURES_IFRETURN_HELPURL);this.hasReturnValue_=!0},mutationToDom:function(){var a=
|
||||
Blockly.utils.xml.createElement("mutation");a.setAttribute("value",Number(this.hasReturnValue_));return a},domToMutation:function(a){this.hasReturnValue_=1==a.getAttribute("value");this.hasReturnValue_||(this.removeInput("VALUE"),this.appendDummyInput("VALUE").appendField(Blockly.Msg.PROCEDURES_DEFRETURN_RETURN))},onchange:function(a){if(this.workspace.isDragging&&!this.workspace.isDragging()){a=!1;var b=this;do{if(-1!=this.FUNCTION_TYPES.indexOf(b.type)){a=!0;break}b=b.getSurroundParent()}while(b);
|
||||
a?("procedures_defnoreturn"==b.type&&this.hasReturnValue_?(this.removeInput("VALUE"),this.appendDummyInput("VALUE").appendField(Blockly.Msg.PROCEDURES_DEFRETURN_RETURN),this.hasReturnValue_=!1):"procedures_defreturn"!=b.type||this.hasReturnValue_||(this.removeInput("VALUE"),this.appendValueInput("VALUE").appendField(Blockly.Msg.PROCEDURES_DEFRETURN_RETURN),this.hasReturnValue_=!0),this.setWarningText(null),this.isInFlyout||this.setEnabled(!0)):(this.setWarningText(Blockly.Msg.PROCEDURES_IFRETURN_WARNING),
|
||||
this.isInFlyout||this.getInheritedDisabled()||this.setEnabled(!1))}},FUNCTION_TYPES:["procedures_defnoreturn","procedures_defreturn"]};Blockly.Blocks.texts={};Blockly.Constants.Text={};Blockly.Constants.Text.HUE=160;
|
||||
Blockly.defineBlocksWithJsonArray([{type:"text",message0:"%1",args0:[{type:"field_input",name:"TEXT",text:""}],output:"String",style:"text_blocks",helpUrl:"%{BKY_TEXT_TEXT_HELPURL}",tooltip:"%{BKY_TEXT_TEXT_TOOLTIP}",extensions:["text_quotes","parent_tooltip_when_inline"]},{type:"text_multiline",message0:"%1 %2",args0:[{type:"field_image",src:"data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAwAAAARCAYAAADpPU2iAAAABGdBTUEAALGPC/xhBQAAAAlwSFlzAAAdhgAAHYYBXaITgQAAABh0RVh0U29mdHdhcmUAcGFpbnQubmV0IDQuMS42/U4J6AAAAP1JREFUOE+Vks0KQUEYhjmRIja4ABtZ2dm5A3t3Ia6AUm7CylYuQRaUhZSlLZJiQbFAyRnPN33y01HOW08z8873zpwzM4F3GWOCruvGIE4/rLaV+Nq1hVGMBqzhqlxgCys4wJA65xnogMHsQ5lujnYHTejBBCK2mE4abjCgMGhNxHgDFWjDSG07kdfVa2pZMf4ZyMAdWmpZMfYOsLiDMYMjlMB+K613QISRhTnITnsYg5yUd0DETmEoMlkFOeIT/A58iyK5E18BuTBfgYXfwNJv4P9/oEBerLylOnRhygmGdPpTTBZAPkde61lbQe4moWUvYUZYLfUNftIY4zwA5X2Z9AYnQrEAAAAASUVORK5CYII=",width:12,
|
||||
height:17,alt:"\u00b6"},{type:"field_multilinetext",name:"TEXT",text:""}],output:"String",style:"text_blocks",helpUrl:"%{BKY_TEXT_TEXT_HELPURL}",tooltip:"%{BKY_TEXT_TEXT_TOOLTIP}",extensions:["parent_tooltip_when_inline"]},{type:"text_join",message0:"",output:"String",style:"text_blocks",helpUrl:"%{BKY_TEXT_JOIN_HELPURL}",tooltip:"%{BKY_TEXT_JOIN_TOOLTIP}",mutator:"text_join_mutator"},{type:"text_create_join_container",message0:"%{BKY_TEXT_CREATE_JOIN_TITLE_JOIN} %1 %2",args0:[{type:"input_dummy"},
|
||||
{type:"input_statement",name:"STACK"}],style:"text_blocks",tooltip:"%{BKY_TEXT_CREATE_JOIN_TOOLTIP}",enableContextMenu:!1},{type:"text_create_join_item",message0:"%{BKY_TEXT_CREATE_JOIN_ITEM_TITLE_ITEM}",previousStatement:null,nextStatement:null,style:"text_blocks",tooltip:"%{BKY_TEXT_CREATE_JOIN_ITEM_TOOLTIP}",enableContextMenu:!1},{type:"text_append",message0:"%{BKY_TEXT_APPEND_TITLE}",args0:[{type:"field_variable",name:"VAR",variable:"%{BKY_TEXT_APPEND_VARIABLE}"},{type:"input_value",name:"TEXT"}],
|
||||
previousStatement:null,nextStatement:null,style:"text_blocks",extensions:["text_append_tooltip"]},{type:"text_length",message0:"%{BKY_TEXT_LENGTH_TITLE}",args0:[{type:"input_value",name:"VALUE",check:["String","Array"]}],output:"Number",style:"text_blocks",tooltip:"%{BKY_TEXT_LENGTH_TOOLTIP}",helpUrl:"%{BKY_TEXT_LENGTH_HELPURL}"},{type:"text_isEmpty",message0:"%{BKY_TEXT_ISEMPTY_TITLE}",args0:[{type:"input_value",name:"VALUE",check:["String","Array"]}],output:"Boolean",style:"text_blocks",tooltip:"%{BKY_TEXT_ISEMPTY_TOOLTIP}",
|
||||
helpUrl:"%{BKY_TEXT_ISEMPTY_HELPURL}"},{type:"text_indexOf",message0:"%{BKY_TEXT_INDEXOF_TITLE}",args0:[{type:"input_value",name:"VALUE",check:"String"},{type:"field_dropdown",name:"END",options:[["%{BKY_TEXT_INDEXOF_OPERATOR_FIRST}","FIRST"],["%{BKY_TEXT_INDEXOF_OPERATOR_LAST}","LAST"]]},{type:"input_value",name:"FIND",check:"String"}],output:"Number",style:"text_blocks",helpUrl:"%{BKY_TEXT_INDEXOF_HELPURL}",inputsInline:!0,extensions:["text_indexOf_tooltip"]},{type:"text_charAt",message0:"%{BKY_TEXT_CHARAT_TITLE}",
|
||||
args0:[{type:"input_value",name:"VALUE",check:"String"},{type:"field_dropdown",name:"WHERE",options:[["%{BKY_TEXT_CHARAT_FROM_START}","FROM_START"],["%{BKY_TEXT_CHARAT_FROM_END}","FROM_END"],["%{BKY_TEXT_CHARAT_FIRST}","FIRST"],["%{BKY_TEXT_CHARAT_LAST}","LAST"],["%{BKY_TEXT_CHARAT_RANDOM}","RANDOM"]]}],output:"String",style:"text_blocks",helpUrl:"%{BKY_TEXT_CHARAT_HELPURL}",inputsInline:!0,mutator:"text_charAt_mutator"}]);
|
||||
Blockly.Blocks.text_getSubstring={init:function(){this.WHERE_OPTIONS_1=[[Blockly.Msg.TEXT_GET_SUBSTRING_START_FROM_START,"FROM_START"],[Blockly.Msg.TEXT_GET_SUBSTRING_START_FROM_END,"FROM_END"],[Blockly.Msg.TEXT_GET_SUBSTRING_START_FIRST,"FIRST"]];this.WHERE_OPTIONS_2=[[Blockly.Msg.TEXT_GET_SUBSTRING_END_FROM_START,"FROM_START"],[Blockly.Msg.TEXT_GET_SUBSTRING_END_FROM_END,"FROM_END"],[Blockly.Msg.TEXT_GET_SUBSTRING_END_LAST,"LAST"]];this.setHelpUrl(Blockly.Msg.TEXT_GET_SUBSTRING_HELPURL);this.setStyle("text_blocks");
|
||||
this.appendValueInput("STRING").setCheck("String").appendField(Blockly.Msg.TEXT_GET_SUBSTRING_INPUT_IN_TEXT);this.appendDummyInput("AT1");this.appendDummyInput("AT2");Blockly.Msg.TEXT_GET_SUBSTRING_TAIL&&this.appendDummyInput("TAIL").appendField(Blockly.Msg.TEXT_GET_SUBSTRING_TAIL);this.setInputsInline(!0);this.setOutput(!0,"String");this.updateAt_(1,!0);this.updateAt_(2,!0);this.setTooltip(Blockly.Msg.TEXT_GET_SUBSTRING_TOOLTIP)},mutationToDom:function(){var a=Blockly.utils.xml.createElement("mutation"),
|
||||
b=this.getInput("AT1").type==Blockly.INPUT_VALUE;a.setAttribute("at1",b);b=this.getInput("AT2").type==Blockly.INPUT_VALUE;a.setAttribute("at2",b);return a},domToMutation:function(a){var b="true"==a.getAttribute("at1");a="true"==a.getAttribute("at2");this.updateAt_(1,b);this.updateAt_(2,a)},updateAt_:function(a,b){this.removeInput("AT"+a);this.removeInput("ORDINAL"+a,!0);b?(this.appendValueInput("AT"+a).setCheck("Number"),Blockly.Msg.ORDINAL_NUMBER_SUFFIX&&this.appendDummyInput("ORDINAL"+a).appendField(Blockly.Msg.ORDINAL_NUMBER_SUFFIX)):
|
||||
this.appendDummyInput("AT"+a);2==a&&Blockly.Msg.TEXT_GET_SUBSTRING_TAIL&&(this.removeInput("TAIL",!0),this.appendDummyInput("TAIL").appendField(Blockly.Msg.TEXT_GET_SUBSTRING_TAIL));var c=new Blockly.FieldDropdown(this["WHERE_OPTIONS_"+a],function(c){var e="FROM_START"==c||"FROM_END"==c;if(e!=b){var d=this.getSourceBlock();d.updateAt_(a,e);d.setFieldValue(c,"WHERE"+a);return null}});this.getInput("AT"+a).appendField(c,"WHERE"+a);1==a&&(this.moveInputBefore("AT1","AT2"),this.getInput("ORDINAL1")&&
|
||||
this.moveInputBefore("ORDINAL1","AT2"))}};Blockly.Blocks.text_changeCase={init:function(){var a=[[Blockly.Msg.TEXT_CHANGECASE_OPERATOR_UPPERCASE,"UPPERCASE"],[Blockly.Msg.TEXT_CHANGECASE_OPERATOR_LOWERCASE,"LOWERCASE"],[Blockly.Msg.TEXT_CHANGECASE_OPERATOR_TITLECASE,"TITLECASE"]];this.setHelpUrl(Blockly.Msg.TEXT_CHANGECASE_HELPURL);this.setStyle("text_blocks");this.appendValueInput("TEXT").setCheck("String").appendField(new Blockly.FieldDropdown(a),"CASE");this.setOutput(!0,"String");this.setTooltip(Blockly.Msg.TEXT_CHANGECASE_TOOLTIP)}};
|
||||
Blockly.Blocks.text_trim={init:function(){var a=[[Blockly.Msg.TEXT_TRIM_OPERATOR_BOTH,"BOTH"],[Blockly.Msg.TEXT_TRIM_OPERATOR_LEFT,"LEFT"],[Blockly.Msg.TEXT_TRIM_OPERATOR_RIGHT,"RIGHT"]];this.setHelpUrl(Blockly.Msg.TEXT_TRIM_HELPURL);this.setStyle("text_blocks");this.appendValueInput("TEXT").setCheck("String").appendField(new Blockly.FieldDropdown(a),"MODE");this.setOutput(!0,"String");this.setTooltip(Blockly.Msg.TEXT_TRIM_TOOLTIP)}};
|
||||
Blockly.Blocks.text_print={init:function(){this.jsonInit({message0:Blockly.Msg.TEXT_PRINT_TITLE,args0:[{type:"input_value",name:"TEXT"}],previousStatement:null,nextStatement:null,style:"text_blocks",tooltip:Blockly.Msg.TEXT_PRINT_TOOLTIP,helpUrl:Blockly.Msg.TEXT_PRINT_HELPURL})}};
|
||||
Blockly.Blocks.text_prompt_ext={init:function(){var a=[[Blockly.Msg.TEXT_PROMPT_TYPE_TEXT,"TEXT"],[Blockly.Msg.TEXT_PROMPT_TYPE_NUMBER,"NUMBER"]];this.setHelpUrl(Blockly.Msg.TEXT_PROMPT_HELPURL);this.setStyle("text_blocks");var b=this;a=new Blockly.FieldDropdown(a,function(a){b.updateType_(a)});this.appendValueInput("TEXT").appendField(a,"TYPE");this.setOutput(!0,"String");this.setTooltip(function(){return"TEXT"==b.getFieldValue("TYPE")?Blockly.Msg.TEXT_PROMPT_TOOLTIP_TEXT:Blockly.Msg.TEXT_PROMPT_TOOLTIP_NUMBER})},
|
||||
updateType_:function(a){this.outputConnection.setCheck("NUMBER"==a?"Number":"String")},mutationToDom:function(){var a=Blockly.utils.xml.createElement("mutation");a.setAttribute("type",this.getFieldValue("TYPE"));return a},domToMutation:function(a){this.updateType_(a.getAttribute("type"))}};
|
||||
Blockly.Blocks.text_prompt={init:function(){this.mixin(Blockly.Constants.Text.QUOTE_IMAGE_MIXIN);var a=[[Blockly.Msg.TEXT_PROMPT_TYPE_TEXT,"TEXT"],[Blockly.Msg.TEXT_PROMPT_TYPE_NUMBER,"NUMBER"]],b=this;this.setHelpUrl(Blockly.Msg.TEXT_PROMPT_HELPURL);this.setStyle("text_blocks");a=new Blockly.FieldDropdown(a,function(a){b.updateType_(a)});this.appendDummyInput().appendField(a,"TYPE").appendField(this.newQuote_(!0)).appendField(new Blockly.FieldTextInput(""),"TEXT").appendField(this.newQuote_(!1));
|
||||
this.setOutput(!0,"String");this.setTooltip(function(){return"TEXT"==b.getFieldValue("TYPE")?Blockly.Msg.TEXT_PROMPT_TOOLTIP_TEXT:Blockly.Msg.TEXT_PROMPT_TOOLTIP_NUMBER})},updateType_:Blockly.Blocks.text_prompt_ext.updateType_,mutationToDom:Blockly.Blocks.text_prompt_ext.mutationToDom,domToMutation:Blockly.Blocks.text_prompt_ext.domToMutation};
|
||||
Blockly.Blocks.text_count={init:function(){this.jsonInit({message0:Blockly.Msg.TEXT_COUNT_MESSAGE0,args0:[{type:"input_value",name:"SUB",check:"String"},{type:"input_value",name:"TEXT",check:"String"}],output:"Number",inputsInline:!0,style:"text_blocks",tooltip:Blockly.Msg.TEXT_COUNT_TOOLTIP,helpUrl:Blockly.Msg.TEXT_COUNT_HELPURL})}};
|
||||
Blockly.Blocks.text_replace={init:function(){this.jsonInit({message0:Blockly.Msg.TEXT_REPLACE_MESSAGE0,args0:[{type:"input_value",name:"FROM",check:"String"},{type:"input_value",name:"TO",check:"String"},{type:"input_value",name:"TEXT",check:"String"}],output:"String",inputsInline:!0,style:"text_blocks",tooltip:Blockly.Msg.TEXT_REPLACE_TOOLTIP,helpUrl:Blockly.Msg.TEXT_REPLACE_HELPURL})}};
|
||||
Blockly.Blocks.text_reverse={init:function(){this.jsonInit({message0:Blockly.Msg.TEXT_REVERSE_MESSAGE0,args0:[{type:"input_value",name:"TEXT",check:"String"}],output:"String",inputsInline:!0,style:"text_blocks",tooltip:Blockly.Msg.TEXT_REVERSE_TOOLTIP,helpUrl:Blockly.Msg.TEXT_REVERSE_HELPURL})}};
|
||||
Blockly.Constants.Text.QUOTE_IMAGE_MIXIN={QUOTE_IMAGE_LEFT_DATAURI:"data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAwAAAAKCAQAAAAqJXdxAAAAn0lEQVQI1z3OMa5BURSF4f/cQhAKjUQhuQmFNwGJEUi0RKN5rU7FHKhpjEH3TEMtkdBSCY1EIv8r7nFX9e29V7EBAOvu7RPjwmWGH/VuF8CyN9/OAdvqIXYLvtRaNjx9mMTDyo+NjAN1HNcl9ZQ5oQMM3dgDUqDo1l8DzvwmtZN7mnD+PkmLa+4mhrxVA9fRowBWmVBhFy5gYEjKMfz9AylsaRRgGzvZAAAAAElFTkSuQmCC",QUOTE_IMAGE_RIGHT_DATAURI:"data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAwAAAAKCAQAAAAqJXdxAAAAqUlEQVQI1z3KvUpCcRiA8ef9E4JNHhI0aFEacm1o0BsI0Slx8wa8gLauoDnoBhq7DcfWhggONDmJJgqCPA7neJ7p934EOOKOnM8Q7PDElo/4x4lFb2DmuUjcUzS3URnGib9qaPNbuXvBO3sGPHJDRG6fGVdMSeWDP2q99FQdFrz26Gu5Tq7dFMzUvbXy8KXeAj57cOklgA+u1B5AoslLtGIHQMaCVnwDnADZIFIrXsoXrgAAAABJRU5ErkJggg==",
|
||||
QUOTE_IMAGE_WIDTH:12,QUOTE_IMAGE_HEIGHT:12,quoteField_:function(a){for(var b=0,c;c=this.inputList[b];b++)for(var d=0,e;e=c.fieldRow[d];d++)if(a==e.name){c.insertFieldAt(d,this.newQuote_(!0));c.insertFieldAt(d+2,this.newQuote_(!1));return}console.warn('field named "'+a+'" not found in '+this.toDevString())},newQuote_:function(a){a=this.RTL?!a:a;return new Blockly.FieldImage(a?this.QUOTE_IMAGE_LEFT_DATAURI:this.QUOTE_IMAGE_RIGHT_DATAURI,this.QUOTE_IMAGE_WIDTH,this.QUOTE_IMAGE_HEIGHT,a?"\u201c":"\u201d")}};
|
||||
Blockly.Constants.Text.TEXT_QUOTES_EXTENSION=function(){this.mixin(Blockly.Constants.Text.QUOTE_IMAGE_MIXIN);this.quoteField_("TEXT")};
|
||||
Blockly.Constants.Text.TEXT_JOIN_MUTATOR_MIXIN={mutationToDom:function(){var a=Blockly.utils.xml.createElement("mutation");a.setAttribute("items",this.itemCount_);return a},domToMutation:function(a){this.itemCount_=parseInt(a.getAttribute("items"),10);this.updateShape_()},decompose:function(a){var b=a.newBlock("text_create_join_container");b.initSvg();for(var c=b.getInput("STACK").connection,d=0;d<this.itemCount_;d++){var e=a.newBlock("text_create_join_item");e.initSvg();c.connect(e.previousConnection);
|
||||
c=e.nextConnection}return b},compose:function(a){var b=a.getInputTargetBlock("STACK");for(a=[];b;)a.push(b.valueConnection_),b=b.nextConnection&&b.nextConnection.targetBlock();for(b=0;b<this.itemCount_;b++){var c=this.getInput("ADD"+b).connection.targetConnection;c&&-1==a.indexOf(c)&&c.disconnect()}this.itemCount_=a.length;this.updateShape_();for(b=0;b<this.itemCount_;b++)Blockly.Mutator.reconnect(a[b],this,"ADD"+b)},saveConnections:function(a){a=a.getInputTargetBlock("STACK");for(var b=0;a;){var c=
|
||||
this.getInput("ADD"+b);a.valueConnection_=c&&c.connection.targetConnection;b++;a=a.nextConnection&&a.nextConnection.targetBlock()}},updateShape_:function(){this.itemCount_&&this.getInput("EMPTY")?this.removeInput("EMPTY"):this.itemCount_||this.getInput("EMPTY")||this.appendDummyInput("EMPTY").appendField(this.newQuote_(!0)).appendField(this.newQuote_(!1));for(var a=0;a<this.itemCount_;a++)if(!this.getInput("ADD"+a)){var b=this.appendValueInput("ADD"+a).setAlign(Blockly.ALIGN_RIGHT);0==a&&b.appendField(Blockly.Msg.TEXT_JOIN_TITLE_CREATEWITH)}for(;this.getInput("ADD"+
|
||||
a);)this.removeInput("ADD"+a),a++}};Blockly.Constants.Text.TEXT_JOIN_EXTENSION=function(){this.mixin(Blockly.Constants.Text.QUOTE_IMAGE_MIXIN);this.itemCount_=2;this.updateShape_();this.setMutator(new Blockly.Mutator(["text_create_join_item"]))};Blockly.Extensions.register("text_append_tooltip",Blockly.Extensions.buildTooltipWithFieldText("%{BKY_TEXT_APPEND_TOOLTIP}","VAR"));
|
||||
Blockly.Constants.Text.TEXT_INDEXOF_TOOLTIP_EXTENSION=function(){var a=this;this.setTooltip(function(){return Blockly.Msg.TEXT_INDEXOF_TOOLTIP.replace("%1",a.workspace.options.oneBasedIndex?"0":"-1")})};
|
||||
Blockly.Constants.Text.TEXT_CHARAT_MUTATOR_MIXIN={mutationToDom:function(){var a=Blockly.utils.xml.createElement("mutation");a.setAttribute("at",!!this.isAt_);return a},domToMutation:function(a){a="false"!=a.getAttribute("at");this.updateAt_(a)},updateAt_:function(a){this.removeInput("AT",!0);this.removeInput("ORDINAL",!0);a&&(this.appendValueInput("AT").setCheck("Number"),Blockly.Msg.ORDINAL_NUMBER_SUFFIX&&this.appendDummyInput("ORDINAL").appendField(Blockly.Msg.ORDINAL_NUMBER_SUFFIX));Blockly.Msg.TEXT_CHARAT_TAIL&&
|
||||
(this.removeInput("TAIL",!0),this.appendDummyInput("TAIL").appendField(Blockly.Msg.TEXT_CHARAT_TAIL));this.isAt_=a}};
|
||||
Blockly.Constants.Text.TEXT_CHARAT_EXTENSION=function(){this.getField("WHERE").setValidator(function(a){a="FROM_START"==a||"FROM_END"==a;a!=this.isAt_&&this.getSourceBlock().updateAt_(a)});this.updateAt_(!0);var a=this;this.setTooltip(function(){var b=a.getFieldValue("WHERE"),c=Blockly.Msg.TEXT_CHARAT_TOOLTIP;("FROM_START"==b||"FROM_END"==b)&&(b="FROM_START"==b?Blockly.Msg.LISTS_INDEX_FROM_START_TOOLTIP:Blockly.Msg.LISTS_INDEX_FROM_END_TOOLTIP)&&(c+=" "+b.replace("%1",a.workspace.options.oneBasedIndex?
|
||||
"#1":"#0"));return c})};Blockly.Extensions.register("text_indexOf_tooltip",Blockly.Constants.Text.TEXT_INDEXOF_TOOLTIP_EXTENSION);Blockly.Extensions.register("text_quotes",Blockly.Constants.Text.TEXT_QUOTES_EXTENSION);Blockly.Extensions.registerMutator("text_join_mutator",Blockly.Constants.Text.TEXT_JOIN_MUTATOR_MIXIN,Blockly.Constants.Text.TEXT_JOIN_EXTENSION);Blockly.Extensions.registerMutator("text_charAt_mutator",Blockly.Constants.Text.TEXT_CHARAT_MUTATOR_MIXIN,Blockly.Constants.Text.TEXT_CHARAT_EXTENSION);Blockly.Blocks.variables={};Blockly.Constants.Variables={};Blockly.Constants.Variables.HUE=330;
|
||||
Blockly.defineBlocksWithJsonArray([{type:"variables_get",message0:"%1",args0:[{type:"field_variable",name:"VAR",variable:"%{BKY_VARIABLES_DEFAULT_NAME}"}],output:null,style:"variable_blocks",helpUrl:"%{BKY_VARIABLES_GET_HELPURL}",tooltip:"%{BKY_VARIABLES_GET_TOOLTIP}",extensions:["contextMenu_variableSetterGetter"]},{type:"variables_set",message0:"%{BKY_VARIABLES_SET}",args0:[{type:"field_variable",name:"VAR",variable:"%{BKY_VARIABLES_DEFAULT_NAME}"},{type:"input_value",name:"VALUE"}],previousStatement:null,
|
||||
nextStatement:null,style:"variable_blocks",tooltip:"%{BKY_VARIABLES_SET_TOOLTIP}",helpUrl:"%{BKY_VARIABLES_SET_HELPURL}",extensions:["contextMenu_variableSetterGetter"]}]);
|
||||
Blockly.Constants.Variables.CUSTOM_CONTEXT_MENU_VARIABLE_GETTER_SETTER_MIXIN={customContextMenu:function(a){if(!this.isInFlyout){if("variables_get"==this.type)var b="variables_set",c=Blockly.Msg.VARIABLES_GET_CREATE_SET;else b="variables_get",c=Blockly.Msg.VARIABLES_SET_CREATE_GET;var d={enabled:0<this.workspace.remainingCapacity()},e=this.getField("VAR").getText();d.text=c.replace("%1",e);c=Blockly.utils.xml.createElement("field");c.setAttribute("name","VAR");c.appendChild(Blockly.utils.xml.createTextNode(e));
|
||||
e=Blockly.utils.xml.createElement("block");e.setAttribute("type",b);e.appendChild(c);d.callback=Blockly.ContextMenu.callbackFactory(this,e);a.push(d)}else if("variables_get"==this.type||"variables_get_reporter"==this.type)b={text:Blockly.Msg.RENAME_VARIABLE,enabled:!0,callback:Blockly.Constants.Variables.RENAME_OPTION_CALLBACK_FACTORY(this)},e=this.getField("VAR").getText(),d={text:Blockly.Msg.DELETE_VARIABLE.replace("%1",e),enabled:!0,callback:Blockly.Constants.Variables.DELETE_OPTION_CALLBACK_FACTORY(this)},
|
||||
a.unshift(b),a.unshift(d)}};Blockly.Constants.Variables.RENAME_OPTION_CALLBACK_FACTORY=function(a){return function(){var b=a.workspace,c=a.getField("VAR").getVariable();Blockly.Variables.renameVariable(b,c)}};Blockly.Constants.Variables.DELETE_OPTION_CALLBACK_FACTORY=function(a){return function(){var b=a.workspace,c=a.getField("VAR").getVariable();b.deleteVariableById(c.getId());b.refreshToolboxSelection()}};Blockly.Extensions.registerMixin("contextMenu_variableSetterGetter",Blockly.Constants.Variables.CUSTOM_CONTEXT_MENU_VARIABLE_GETTER_SETTER_MIXIN);Blockly.Constants.VariablesDynamic={};Blockly.Constants.VariablesDynamic.HUE=310;
|
||||
Blockly.defineBlocksWithJsonArray([{type:"variables_get_dynamic",message0:"%1",args0:[{type:"field_variable",name:"VAR",variable:"%{BKY_VARIABLES_DEFAULT_NAME}"}],output:null,style:"variable_dynamic_blocks",helpUrl:"%{BKY_VARIABLES_GET_HELPURL}",tooltip:"%{BKY_VARIABLES_GET_TOOLTIP}",extensions:["contextMenu_variableDynamicSetterGetter"]},{type:"variables_set_dynamic",message0:"%{BKY_VARIABLES_SET}",args0:[{type:"field_variable",name:"VAR",variable:"%{BKY_VARIABLES_DEFAULT_NAME}"},{type:"input_value",
|
||||
name:"VALUE"}],previousStatement:null,nextStatement:null,style:"variable_dynamic_blocks",tooltip:"%{BKY_VARIABLES_SET_TOOLTIP}",helpUrl:"%{BKY_VARIABLES_SET_HELPURL}",extensions:["contextMenu_variableDynamicSetterGetter"]}]);
|
||||
Blockly.Constants.VariablesDynamic.CUSTOM_CONTEXT_MENU_VARIABLE_GETTER_SETTER_MIXIN={customContextMenu:function(a){if(!this.isInFlyout){var b=this.getFieldValue("VAR");var c=this.workspace.getVariableById(b).type;if("variables_get_dynamic"==this.type){b="variables_set_dynamic";var d=Blockly.Msg.VARIABLES_GET_CREATE_SET}else b="variables_get_dynamic",d=Blockly.Msg.VARIABLES_SET_CREATE_GET;var e={enabled:0<this.workspace.remainingCapacity()},f=this.getField("VAR").getText();e.text=d.replace("%1",f);
|
||||
d=Blockly.utils.xml.createElement("field");d.setAttribute("name","VAR");d.setAttribute("variabletype",c);d.appendChild(Blockly.utils.xml.createTextNode(f));f=Blockly.utils.xml.createElement("block");f.setAttribute("type",b);f.appendChild(d);e.callback=Blockly.ContextMenu.callbackFactory(this,f);a.push(e)}else if("variables_get_dynamic"==this.type||"variables_get_reporter_dynamic"==this.type)b={text:Blockly.Msg.RENAME_VARIABLE,enabled:!0,callback:Blockly.Constants.Variables.RENAME_OPTION_CALLBACK_FACTORY(this)},
|
||||
f=this.getField("VAR").getText(),e={text:Blockly.Msg.DELETE_VARIABLE.replace("%1",f),enabled:!0,callback:Blockly.Constants.Variables.DELETE_OPTION_CALLBACK_FACTORY(this)},a.unshift(b),a.unshift(e)},onchange:function(a){a=this.getFieldValue("VAR");a=Blockly.Variables.getVariable(this.workspace,a);"variables_get_dynamic"==this.type?this.outputConnection.setCheck(a.type):this.getInput("VALUE").connection.setCheck(a.type)}};
|
||||
Blockly.Constants.VariablesDynamic.RENAME_OPTION_CALLBACK_FACTORY=function(a){return function(){var b=a.workspace,c=a.getField("VAR").getVariable();Blockly.Variables.renameVariable(b,c)}};Blockly.Constants.VariablesDynamic.DELETE_OPTION_CALLBACK_FACTORY=function(a){return function(){var b=a.workspace,c=a.getField("VAR").getVariable();b.deleteVariableById(c.getId());b.refreshToolboxSelection()}};Blockly.Extensions.registerMixin("contextMenu_variableDynamicSetterGetter",Blockly.Constants.VariablesDynamic.CUSTOM_CONTEXT_MENU_VARIABLE_GETTER_SETTER_MIXIN);
|
||||
return Blockly.Blocks;
|
||||
}));
|
||||
|
||||
|
||||
//# sourceMappingURL=blocks_compressed.js.map
|
||||
1
clover_blocks/www/blockly/blocks_compressed.js.map
Executable file
BIN
clover_blocks/www/blockly/media/1x1.gif
Executable file
|
After Width: | Height: | Size: 43 B |
BIN
clover_blocks/www/blockly/media/click.mp3
Executable file
BIN
clover_blocks/www/blockly/media/click.ogg
Executable file
BIN
clover_blocks/www/blockly/media/click.wav
Executable file
BIN
clover_blocks/www/blockly/media/delete.mp3
Executable file
BIN
clover_blocks/www/blockly/media/delete.ogg
Executable file
BIN
clover_blocks/www/blockly/media/delete.wav
Executable file
BIN
clover_blocks/www/blockly/media/disconnect.mp3
Executable file
BIN
clover_blocks/www/blockly/media/disconnect.ogg
Executable file
BIN
clover_blocks/www/blockly/media/disconnect.wav
Executable file
1
clover_blocks/www/blockly/media/dropdown-arrow.svg
Executable file
@@ -0,0 +1 @@
|
||||
<svg id="Layer_1" data-name="Layer 1" xmlns="http://www.w3.org/2000/svg" width="12.71" height="8.79" viewBox="0 0 12.71 8.79"><title>dropdown-arrow</title><g opacity="0.1"><path d="M12.71,2.44A2.41,2.41,0,0,1,12,4.16L8.08,8.08a2.45,2.45,0,0,1-3.45,0L0.72,4.16A2.42,2.42,0,0,1,0,2.44,2.48,2.48,0,0,1,.71.71C1,0.47,1.43,0,6.36,0S11.75,0.46,12,.71A2.44,2.44,0,0,1,12.71,2.44Z" fill="#231f20"/></g><path d="M6.36,7.79a1.43,1.43,0,0,1-1-.42L1.42,3.45a1.44,1.44,0,0,1,0-2c0.56-.56,9.31-0.56,9.87,0a1.44,1.44,0,0,1,0,2L7.37,7.37A1.43,1.43,0,0,1,6.36,7.79Z" fill="#fff"/></svg>
|
||||
|
After Width: | Height: | Size: 569 B |
BIN
clover_blocks/www/blockly/media/handclosed.cur
Executable file
|
After Width: | Height: | Size: 326 B |
BIN
clover_blocks/www/blockly/media/handdelete.cur
Executable file
|
After Width: | Height: | Size: 766 B |
BIN
clover_blocks/www/blockly/media/handopen.cur
Executable file
|
After Width: | Height: | Size: 198 B |
BIN
clover_blocks/www/blockly/media/pilcrow.png
Executable file
|
After Width: | Height: | Size: 1010 B |
BIN
clover_blocks/www/blockly/media/quote0.png
Executable file
|
After Width: | Height: | Size: 771 B |
BIN
clover_blocks/www/blockly/media/quote1.png
Executable file
|
After Width: | Height: | Size: 738 B |
BIN
clover_blocks/www/blockly/media/sprites.png
Executable file
|
After Width: | Height: | Size: 2.5 KiB |
74
clover_blocks/www/blockly/media/sprites.svg
Executable file
@@ -0,0 +1,74 @@
|
||||
<?xml version="1.0" encoding="utf-8" standalone="no"?>
|
||||
<svg xmlns="http://www.w3.org/2000/svg" version="1.1" width="96px" height="124px">
|
||||
<style type="text/css">
|
||||
#background {
|
||||
fill: none;
|
||||
}
|
||||
.arrows {
|
||||
fill: #000;
|
||||
stroke: none;
|
||||
}
|
||||
.selected>.arrows {
|
||||
fill: #fff;
|
||||
}
|
||||
.checkmark {
|
||||
fill: #000;
|
||||
font-family: sans-serif;
|
||||
font-size: 10pt;
|
||||
text-anchor: middle;
|
||||
}
|
||||
.trash {
|
||||
fill: #888;
|
||||
}
|
||||
.zoom {
|
||||
fill: none;
|
||||
stroke: #888;
|
||||
stroke-width: 2;
|
||||
stroke-linecap: round;
|
||||
}
|
||||
.zoom>.center {
|
||||
fill: #888;
|
||||
stroke-width: 0;
|
||||
}
|
||||
</style>
|
||||
<rect id="background" width="96" height="124" x="0" y="0" />
|
||||
|
||||
<g>
|
||||
<path class="arrows" d="M 13,1.5 13,14.5 1.74,8 z" />
|
||||
<path class="arrows" d="M 17.5,3 30.5,3 24,14.26 z" />
|
||||
<path class="arrows" d="M 35,1.5 35,14.5 46.26,8 z" />
|
||||
</g>
|
||||
<g class="selected" transform="translate(0, 16)">
|
||||
<path class="arrows" d="M 13,1.5 13,14.5 1.74,8 z" />
|
||||
<path class="arrows" d="M 17.5,3 30.5,3 24,14.26 z" />
|
||||
<path class="arrows" d="M 35,1.5 35,14.5 46.26,8 z" />
|
||||
</g>
|
||||
|
||||
<text class="checkmark" x="55.5" y="28">✓</text>
|
||||
|
||||
<g class="trash">
|
||||
<path d="M 2,41 v 6 h 42 v -6 h -10.5 l -3,-3 h -15 l -3,3 z" />
|
||||
<rect width="36" height="20" x="5" y="50" />
|
||||
<rect width="36" height="42" x="5" y="50" rx="4" ry="4" />
|
||||
</g>
|
||||
|
||||
<g class="zoom">
|
||||
<circle r="11.5" cx="16" cy="108" />
|
||||
<circle r="4.3" cx="16" cy="108" class="center" />
|
||||
<path d="m 28,108 h3" />
|
||||
<path d="m 1,108 h3" />
|
||||
<path d="m 16,120 v3" />
|
||||
<path d="m 16,93 v3" />
|
||||
</g>
|
||||
|
||||
<g class="zoom">
|
||||
<circle r="15" cx="48" cy="108" />
|
||||
<path d="m 48,101.6 v12.8" />
|
||||
<path d="m 41.6,108 h12.8" />
|
||||
</g>
|
||||
|
||||
<g class="zoom">
|
||||
<circle r="15" cx="80" cy="108" />
|
||||
<path d="m 73.6,108 h12.8" />
|
||||
</g>
|
||||
</svg>
|
||||
|
After Width: | Height: | Size: 1.7 KiB |
434
clover_blocks/www/blockly/msg/js/en.js
Executable file
@@ -0,0 +1,434 @@
|
||||
// This file was automatically generated. Do not modify.
|
||||
|
||||
'use strict';
|
||||
|
||||
Blockly.Msg["ADD_COMMENT"] = "Add Comment";
|
||||
Blockly.Msg["CANNOT_DELETE_VARIABLE_PROCEDURE"] = "Can't delete the variable '%1' because it's part of the definition of the function '%2'";
|
||||
Blockly.Msg["CHANGE_VALUE_TITLE"] = "Change value:";
|
||||
Blockly.Msg["CLEAN_UP"] = "Clean up Blocks";
|
||||
Blockly.Msg["COLLAPSED_WARNINGS_WARNING"] = "Collapsed blocks contain warnings.";
|
||||
Blockly.Msg["COLLAPSE_ALL"] = "Collapse Blocks";
|
||||
Blockly.Msg["COLLAPSE_BLOCK"] = "Collapse Block";
|
||||
Blockly.Msg["COLOUR_BLEND_COLOUR1"] = "colour 1";
|
||||
Blockly.Msg["COLOUR_BLEND_COLOUR2"] = "colour 2";
|
||||
Blockly.Msg["COLOUR_BLEND_HELPURL"] = "https://meyerweb.com/eric/tools/color-blend/#:::rgbp";
|
||||
Blockly.Msg["COLOUR_BLEND_RATIO"] = "ratio";
|
||||
Blockly.Msg["COLOUR_BLEND_TITLE"] = "blend";
|
||||
Blockly.Msg["COLOUR_BLEND_TOOLTIP"] = "Blends two colours together with a given ratio (0.0 - 1.0).";
|
||||
Blockly.Msg["COLOUR_PICKER_HELPURL"] = "https://en.wikipedia.org/wiki/Color";
|
||||
Blockly.Msg["COLOUR_PICKER_TOOLTIP"] = "Choose a colour from the palette.";
|
||||
Blockly.Msg["COLOUR_RANDOM_HELPURL"] = "http://randomcolour.com";
|
||||
Blockly.Msg["COLOUR_RANDOM_TITLE"] = "random colour";
|
||||
Blockly.Msg["COLOUR_RANDOM_TOOLTIP"] = "Choose a colour at random.";
|
||||
Blockly.Msg["COLOUR_RGB_BLUE"] = "blue";
|
||||
Blockly.Msg["COLOUR_RGB_GREEN"] = "green";
|
||||
Blockly.Msg["COLOUR_RGB_HELPURL"] = "https://www.december.com/html/spec/colorpercompact.html";
|
||||
Blockly.Msg["COLOUR_RGB_RED"] = "red";
|
||||
Blockly.Msg["COLOUR_RGB_TITLE"] = "colour with";
|
||||
Blockly.Msg["COLOUR_RGB_TOOLTIP"] = "Create a colour with the specified amount of red, green, and blue. All values must be between 0 and 100.";
|
||||
Blockly.Msg["CONTROLS_FLOW_STATEMENTS_HELPURL"] = "https://github.com/google/blockly/wiki/Loops#loop-termination-blocks";
|
||||
Blockly.Msg["CONTROLS_FLOW_STATEMENTS_OPERATOR_BREAK"] = "break out of loop";
|
||||
Blockly.Msg["CONTROLS_FLOW_STATEMENTS_OPERATOR_CONTINUE"] = "continue with next iteration of loop";
|
||||
Blockly.Msg["CONTROLS_FLOW_STATEMENTS_TOOLTIP_BREAK"] = "Break out of the containing loop.";
|
||||
Blockly.Msg["CONTROLS_FLOW_STATEMENTS_TOOLTIP_CONTINUE"] = "Skip the rest of this loop, and continue with the next iteration.";
|
||||
Blockly.Msg["CONTROLS_FLOW_STATEMENTS_WARNING"] = "Warning: This block may only be used within a loop.";
|
||||
Blockly.Msg["CONTROLS_FOREACH_HELPURL"] = "https://github.com/google/blockly/wiki/Loops#for-each";
|
||||
Blockly.Msg["CONTROLS_FOREACH_TITLE"] = "for each item %1 in list %2";
|
||||
Blockly.Msg["CONTROLS_FOREACH_TOOLTIP"] = "For each item in a list, set the variable '%1' to the item, and then do some statements.";
|
||||
Blockly.Msg["CONTROLS_FOR_HELPURL"] = "https://github.com/google/blockly/wiki/Loops#count-with";
|
||||
Blockly.Msg["CONTROLS_FOR_TITLE"] = "count with %1 from %2 to %3 by %4";
|
||||
Blockly.Msg["CONTROLS_FOR_TOOLTIP"] = "Have the variable '%1' take on the values from the start number to the end number, counting by the specified interval, and do the specified blocks.";
|
||||
Blockly.Msg["CONTROLS_IF_ELSEIF_TOOLTIP"] = "Add a condition to the if block.";
|
||||
Blockly.Msg["CONTROLS_IF_ELSE_TOOLTIP"] = "Add a final, catch-all condition to the if block.";
|
||||
Blockly.Msg["CONTROLS_IF_HELPURL"] = "https://github.com/google/blockly/wiki/IfElse";
|
||||
Blockly.Msg["CONTROLS_IF_IF_TOOLTIP"] = "Add, remove, or reorder sections to reconfigure this if block.";
|
||||
Blockly.Msg["CONTROLS_IF_MSG_ELSE"] = "else";
|
||||
Blockly.Msg["CONTROLS_IF_MSG_ELSEIF"] = "else if";
|
||||
Blockly.Msg["CONTROLS_IF_MSG_IF"] = "if";
|
||||
Blockly.Msg["CONTROLS_IF_TOOLTIP_1"] = "If a value is true, then do some statements.";
|
||||
Blockly.Msg["CONTROLS_IF_TOOLTIP_2"] = "If a value is true, then do the first block of statements. Otherwise, do the second block of statements.";
|
||||
Blockly.Msg["CONTROLS_IF_TOOLTIP_3"] = "If the first value is true, then do the first block of statements. Otherwise, if the second value is true, do the second block of statements.";
|
||||
Blockly.Msg["CONTROLS_IF_TOOLTIP_4"] = "If the first value is true, then do the first block of statements. Otherwise, if the second value is true, do the second block of statements. If none of the values are true, do the last block of statements.";
|
||||
Blockly.Msg["CONTROLS_REPEAT_HELPURL"] = "https://en.wikipedia.org/wiki/For_loop";
|
||||
Blockly.Msg["CONTROLS_REPEAT_INPUT_DO"] = "do";
|
||||
Blockly.Msg["CONTROLS_REPEAT_TITLE"] = "repeat %1 times";
|
||||
Blockly.Msg["CONTROLS_REPEAT_TOOLTIP"] = "Do some statements several times.";
|
||||
Blockly.Msg["CONTROLS_WHILEUNTIL_HELPURL"] = "https://github.com/google/blockly/wiki/Loops#repeat";
|
||||
Blockly.Msg["CONTROLS_WHILEUNTIL_OPERATOR_UNTIL"] = "repeat until";
|
||||
Blockly.Msg["CONTROLS_WHILEUNTIL_OPERATOR_WHILE"] = "repeat while";
|
||||
Blockly.Msg["CONTROLS_WHILEUNTIL_TOOLTIP_UNTIL"] = "While a value is false, then do some statements.";
|
||||
Blockly.Msg["CONTROLS_WHILEUNTIL_TOOLTIP_WHILE"] = "While a value is true, then do some statements.";
|
||||
Blockly.Msg["DELETE_ALL_BLOCKS"] = "Delete all %1 blocks?";
|
||||
Blockly.Msg["DELETE_BLOCK"] = "Delete Block";
|
||||
Blockly.Msg["DELETE_VARIABLE"] = "Delete the '%1' variable";
|
||||
Blockly.Msg["DELETE_VARIABLE_CONFIRMATION"] = "Delete %1 uses of the '%2' variable?";
|
||||
Blockly.Msg["DELETE_X_BLOCKS"] = "Delete %1 Blocks";
|
||||
Blockly.Msg["DISABLE_BLOCK"] = "Disable Block";
|
||||
Blockly.Msg["DUPLICATE_BLOCK"] = "Duplicate";
|
||||
Blockly.Msg["DUPLICATE_COMMENT"] = "Duplicate Comment";
|
||||
Blockly.Msg["ENABLE_BLOCK"] = "Enable Block";
|
||||
Blockly.Msg["EXPAND_ALL"] = "Expand Blocks";
|
||||
Blockly.Msg["EXPAND_BLOCK"] = "Expand Block";
|
||||
Blockly.Msg["EXTERNAL_INPUTS"] = "External Inputs";
|
||||
Blockly.Msg["HELP"] = "Help";
|
||||
Blockly.Msg["INLINE_INPUTS"] = "Inline Inputs";
|
||||
Blockly.Msg["IOS_CANCEL"] = "Cancel";
|
||||
Blockly.Msg["IOS_ERROR"] = "Error";
|
||||
Blockly.Msg["IOS_OK"] = "OK";
|
||||
Blockly.Msg["IOS_PROCEDURES_ADD_INPUT"] = "+ Add Input";
|
||||
Blockly.Msg["IOS_PROCEDURES_ALLOW_STATEMENTS"] = "Allow statements";
|
||||
Blockly.Msg["IOS_PROCEDURES_DUPLICATE_INPUTS_ERROR"] = "This function has duplicate inputs.";
|
||||
Blockly.Msg["IOS_PROCEDURES_INPUTS"] = "INPUTS";
|
||||
Blockly.Msg["IOS_VARIABLES_ADD_BUTTON"] = "Add";
|
||||
Blockly.Msg["IOS_VARIABLES_ADD_VARIABLE"] = "+ Add Variable";
|
||||
Blockly.Msg["IOS_VARIABLES_DELETE_BUTTON"] = "Delete";
|
||||
Blockly.Msg["IOS_VARIABLES_EMPTY_NAME_ERROR"] = "You can't use an empty variable name.";
|
||||
Blockly.Msg["IOS_VARIABLES_RENAME_BUTTON"] = "Rename";
|
||||
Blockly.Msg["IOS_VARIABLES_VARIABLE_NAME"] = "Variable name";
|
||||
Blockly.Msg["LISTS_CREATE_EMPTY_HELPURL"] = "https://github.com/google/blockly/wiki/Lists#create-empty-list";
|
||||
Blockly.Msg["LISTS_CREATE_EMPTY_TITLE"] = "create empty list";
|
||||
Blockly.Msg["LISTS_CREATE_EMPTY_TOOLTIP"] = "Returns a list, of length 0, containing no data records";
|
||||
Blockly.Msg["LISTS_CREATE_WITH_CONTAINER_TITLE_ADD"] = "list";
|
||||
Blockly.Msg["LISTS_CREATE_WITH_CONTAINER_TOOLTIP"] = "Add, remove, or reorder sections to reconfigure this list block.";
|
||||
Blockly.Msg["LISTS_CREATE_WITH_HELPURL"] = "https://github.com/google/blockly/wiki/Lists#create-list-with";
|
||||
Blockly.Msg["LISTS_CREATE_WITH_INPUT_WITH"] = "create list with";
|
||||
Blockly.Msg["LISTS_CREATE_WITH_ITEM_TOOLTIP"] = "Add an item to the list.";
|
||||
Blockly.Msg["LISTS_CREATE_WITH_TOOLTIP"] = "Create a list with any number of items.";
|
||||
Blockly.Msg["LISTS_GET_INDEX_FIRST"] = "first";
|
||||
Blockly.Msg["LISTS_GET_INDEX_FROM_END"] = "# from end";
|
||||
Blockly.Msg["LISTS_GET_INDEX_FROM_START"] = "#";
|
||||
Blockly.Msg["LISTS_GET_INDEX_GET"] = "get";
|
||||
Blockly.Msg["LISTS_GET_INDEX_GET_REMOVE"] = "get and remove";
|
||||
Blockly.Msg["LISTS_GET_INDEX_LAST"] = "last";
|
||||
Blockly.Msg["LISTS_GET_INDEX_RANDOM"] = "random";
|
||||
Blockly.Msg["LISTS_GET_INDEX_REMOVE"] = "remove";
|
||||
Blockly.Msg["LISTS_GET_INDEX_TAIL"] = "";
|
||||
Blockly.Msg["LISTS_GET_INDEX_TOOLTIP_GET_FIRST"] = "Returns the first item in a list.";
|
||||
Blockly.Msg["LISTS_GET_INDEX_TOOLTIP_GET_FROM"] = "Returns the item at the specified position in a list.";
|
||||
Blockly.Msg["LISTS_GET_INDEX_TOOLTIP_GET_LAST"] = "Returns the last item in a list.";
|
||||
Blockly.Msg["LISTS_GET_INDEX_TOOLTIP_GET_RANDOM"] = "Returns a random item in a list.";
|
||||
Blockly.Msg["LISTS_GET_INDEX_TOOLTIP_GET_REMOVE_FIRST"] = "Removes and returns the first item in a list.";
|
||||
Blockly.Msg["LISTS_GET_INDEX_TOOLTIP_GET_REMOVE_FROM"] = "Removes and returns the item at the specified position in a list.";
|
||||
Blockly.Msg["LISTS_GET_INDEX_TOOLTIP_GET_REMOVE_LAST"] = "Removes and returns the last item in a list.";
|
||||
Blockly.Msg["LISTS_GET_INDEX_TOOLTIP_GET_REMOVE_RANDOM"] = "Removes and returns a random item in a list.";
|
||||
Blockly.Msg["LISTS_GET_INDEX_TOOLTIP_REMOVE_FIRST"] = "Removes the first item in a list.";
|
||||
Blockly.Msg["LISTS_GET_INDEX_TOOLTIP_REMOVE_FROM"] = "Removes the item at the specified position in a list.";
|
||||
Blockly.Msg["LISTS_GET_INDEX_TOOLTIP_REMOVE_LAST"] = "Removes the last item in a list.";
|
||||
Blockly.Msg["LISTS_GET_INDEX_TOOLTIP_REMOVE_RANDOM"] = "Removes a random item in a list.";
|
||||
Blockly.Msg["LISTS_GET_SUBLIST_END_FROM_END"] = "to # from end";
|
||||
Blockly.Msg["LISTS_GET_SUBLIST_END_FROM_START"] = "to #";
|
||||
Blockly.Msg["LISTS_GET_SUBLIST_END_LAST"] = "to last";
|
||||
Blockly.Msg["LISTS_GET_SUBLIST_HELPURL"] = "https://github.com/google/blockly/wiki/Lists#getting-a-sublist";
|
||||
Blockly.Msg["LISTS_GET_SUBLIST_START_FIRST"] = "get sub-list from first";
|
||||
Blockly.Msg["LISTS_GET_SUBLIST_START_FROM_END"] = "get sub-list from # from end";
|
||||
Blockly.Msg["LISTS_GET_SUBLIST_START_FROM_START"] = "get sub-list from #";
|
||||
Blockly.Msg["LISTS_GET_SUBLIST_TAIL"] = "";
|
||||
Blockly.Msg["LISTS_GET_SUBLIST_TOOLTIP"] = "Creates a copy of the specified portion of a list.";
|
||||
Blockly.Msg["LISTS_INDEX_FROM_END_TOOLTIP"] = "%1 is the last item.";
|
||||
Blockly.Msg["LISTS_INDEX_FROM_START_TOOLTIP"] = "%1 is the first item.";
|
||||
Blockly.Msg["LISTS_INDEX_OF_FIRST"] = "find first occurrence of item";
|
||||
Blockly.Msg["LISTS_INDEX_OF_HELPURL"] = "https://github.com/google/blockly/wiki/Lists#getting-items-from-a-list";
|
||||
Blockly.Msg["LISTS_INDEX_OF_LAST"] = "find last occurrence of item";
|
||||
Blockly.Msg["LISTS_INDEX_OF_TOOLTIP"] = "Returns the index of the first/last occurrence of the item in the list. Returns %1 if item is not found.";
|
||||
Blockly.Msg["LISTS_INLIST"] = "in list";
|
||||
Blockly.Msg["LISTS_ISEMPTY_HELPURL"] = "https://github.com/google/blockly/wiki/Lists#is-empty";
|
||||
Blockly.Msg["LISTS_ISEMPTY_TITLE"] = "%1 is empty";
|
||||
Blockly.Msg["LISTS_ISEMPTY_TOOLTIP"] = "Returns true if the list is empty.";
|
||||
Blockly.Msg["LISTS_LENGTH_HELPURL"] = "https://github.com/google/blockly/wiki/Lists#length-of";
|
||||
Blockly.Msg["LISTS_LENGTH_TITLE"] = "length of %1";
|
||||
Blockly.Msg["LISTS_LENGTH_TOOLTIP"] = "Returns the length of a list.";
|
||||
Blockly.Msg["LISTS_REPEAT_HELPURL"] = "https://github.com/google/blockly/wiki/Lists#create-list-with";
|
||||
Blockly.Msg["LISTS_REPEAT_TITLE"] = "create list with item %1 repeated %2 times";
|
||||
Blockly.Msg["LISTS_REPEAT_TOOLTIP"] = "Creates a list consisting of the given value repeated the specified number of times.";
|
||||
Blockly.Msg["LISTS_REVERSE_HELPURL"] = "https://github.com/google/blockly/wiki/Lists#reversing-a-list";
|
||||
Blockly.Msg["LISTS_REVERSE_MESSAGE0"] = "reverse %1";
|
||||
Blockly.Msg["LISTS_REVERSE_TOOLTIP"] = "Reverse a copy of a list.";
|
||||
Blockly.Msg["LISTS_SET_INDEX_HELPURL"] = "https://github.com/google/blockly/wiki/Lists#in-list--set";
|
||||
Blockly.Msg["LISTS_SET_INDEX_INPUT_TO"] = "as";
|
||||
Blockly.Msg["LISTS_SET_INDEX_INSERT"] = "insert at";
|
||||
Blockly.Msg["LISTS_SET_INDEX_SET"] = "set";
|
||||
Blockly.Msg["LISTS_SET_INDEX_TOOLTIP_INSERT_FIRST"] = "Inserts the item at the start of a list.";
|
||||
Blockly.Msg["LISTS_SET_INDEX_TOOLTIP_INSERT_FROM"] = "Inserts the item at the specified position in a list.";
|
||||
Blockly.Msg["LISTS_SET_INDEX_TOOLTIP_INSERT_LAST"] = "Append the item to the end of a list.";
|
||||
Blockly.Msg["LISTS_SET_INDEX_TOOLTIP_INSERT_RANDOM"] = "Inserts the item randomly in a list.";
|
||||
Blockly.Msg["LISTS_SET_INDEX_TOOLTIP_SET_FIRST"] = "Sets the first item in a list.";
|
||||
Blockly.Msg["LISTS_SET_INDEX_TOOLTIP_SET_FROM"] = "Sets the item at the specified position in a list.";
|
||||
Blockly.Msg["LISTS_SET_INDEX_TOOLTIP_SET_LAST"] = "Sets the last item in a list.";
|
||||
Blockly.Msg["LISTS_SET_INDEX_TOOLTIP_SET_RANDOM"] = "Sets a random item in a list.";
|
||||
Blockly.Msg["LISTS_SORT_HELPURL"] = "https://github.com/google/blockly/wiki/Lists#sorting-a-list";
|
||||
Blockly.Msg["LISTS_SORT_ORDER_ASCENDING"] = "ascending";
|
||||
Blockly.Msg["LISTS_SORT_ORDER_DESCENDING"] = "descending";
|
||||
Blockly.Msg["LISTS_SORT_TITLE"] = "sort %1 %2 %3";
|
||||
Blockly.Msg["LISTS_SORT_TOOLTIP"] = "Sort a copy of a list.";
|
||||
Blockly.Msg["LISTS_SORT_TYPE_IGNORECASE"] = "alphabetic, ignore case";
|
||||
Blockly.Msg["LISTS_SORT_TYPE_NUMERIC"] = "numeric";
|
||||
Blockly.Msg["LISTS_SORT_TYPE_TEXT"] = "alphabetic";
|
||||
Blockly.Msg["LISTS_SPLIT_HELPURL"] = "https://github.com/google/blockly/wiki/Lists#splitting-strings-and-joining-lists";
|
||||
Blockly.Msg["LISTS_SPLIT_LIST_FROM_TEXT"] = "make list from text";
|
||||
Blockly.Msg["LISTS_SPLIT_TEXT_FROM_LIST"] = "make text from list";
|
||||
Blockly.Msg["LISTS_SPLIT_TOOLTIP_JOIN"] = "Join a list of texts into one text, separated by a delimiter.";
|
||||
Blockly.Msg["LISTS_SPLIT_TOOLTIP_SPLIT"] = "Split text into a list of texts, breaking at each delimiter.";
|
||||
Blockly.Msg["LISTS_SPLIT_WITH_DELIMITER"] = "with delimiter";
|
||||
Blockly.Msg["LOGIC_BOOLEAN_FALSE"] = "false";
|
||||
Blockly.Msg["LOGIC_BOOLEAN_HELPURL"] = "https://github.com/google/blockly/wiki/Logic#values";
|
||||
Blockly.Msg["LOGIC_BOOLEAN_TOOLTIP"] = "Returns either true or false.";
|
||||
Blockly.Msg["LOGIC_BOOLEAN_TRUE"] = "true";
|
||||
Blockly.Msg["LOGIC_COMPARE_HELPURL"] = "https://en.wikipedia.org/wiki/Inequality_(mathematics)";
|
||||
Blockly.Msg["LOGIC_COMPARE_TOOLTIP_EQ"] = "Return true if both inputs equal each other.";
|
||||
Blockly.Msg["LOGIC_COMPARE_TOOLTIP_GT"] = "Return true if the first input is greater than the second input.";
|
||||
Blockly.Msg["LOGIC_COMPARE_TOOLTIP_GTE"] = "Return true if the first input is greater than or equal to the second input.";
|
||||
Blockly.Msg["LOGIC_COMPARE_TOOLTIP_LT"] = "Return true if the first input is smaller than the second input.";
|
||||
Blockly.Msg["LOGIC_COMPARE_TOOLTIP_LTE"] = "Return true if the first input is smaller than or equal to the second input.";
|
||||
Blockly.Msg["LOGIC_COMPARE_TOOLTIP_NEQ"] = "Return true if both inputs are not equal to each other.";
|
||||
Blockly.Msg["LOGIC_NEGATE_HELPURL"] = "https://github.com/google/blockly/wiki/Logic#not";
|
||||
Blockly.Msg["LOGIC_NEGATE_TITLE"] = "not %1";
|
||||
Blockly.Msg["LOGIC_NEGATE_TOOLTIP"] = "Returns true if the input is false. Returns false if the input is true.";
|
||||
Blockly.Msg["LOGIC_NULL"] = "null";
|
||||
Blockly.Msg["LOGIC_NULL_HELPURL"] = "https://en.wikipedia.org/wiki/Nullable_type";
|
||||
Blockly.Msg["LOGIC_NULL_TOOLTIP"] = "Returns null.";
|
||||
Blockly.Msg["LOGIC_OPERATION_AND"] = "and";
|
||||
Blockly.Msg["LOGIC_OPERATION_HELPURL"] = "https://github.com/google/blockly/wiki/Logic#logical-operations";
|
||||
Blockly.Msg["LOGIC_OPERATION_OR"] = "or";
|
||||
Blockly.Msg["LOGIC_OPERATION_TOOLTIP_AND"] = "Return true if both inputs are true.";
|
||||
Blockly.Msg["LOGIC_OPERATION_TOOLTIP_OR"] = "Return true if at least one of the inputs is true.";
|
||||
Blockly.Msg["LOGIC_TERNARY_CONDITION"] = "test";
|
||||
Blockly.Msg["LOGIC_TERNARY_HELPURL"] = "https://en.wikipedia.org/wiki/%3F:";
|
||||
Blockly.Msg["LOGIC_TERNARY_IF_FALSE"] = "if false";
|
||||
Blockly.Msg["LOGIC_TERNARY_IF_TRUE"] = "if true";
|
||||
Blockly.Msg["LOGIC_TERNARY_TOOLTIP"] = "Check the condition in 'test'. If the condition is true, returns the 'if true' value; otherwise returns the 'if false' value.";
|
||||
Blockly.Msg["MATH_ADDITION_SYMBOL"] = "+";
|
||||
Blockly.Msg["MATH_ARITHMETIC_HELPURL"] = "https://en.wikipedia.org/wiki/Arithmetic";
|
||||
Blockly.Msg["MATH_ARITHMETIC_TOOLTIP_ADD"] = "Return the sum of the two numbers.";
|
||||
Blockly.Msg["MATH_ARITHMETIC_TOOLTIP_DIVIDE"] = "Return the quotient of the two numbers.";
|
||||
Blockly.Msg["MATH_ARITHMETIC_TOOLTIP_MINUS"] = "Return the difference of the two numbers.";
|
||||
Blockly.Msg["MATH_ARITHMETIC_TOOLTIP_MULTIPLY"] = "Return the product of the two numbers.";
|
||||
Blockly.Msg["MATH_ARITHMETIC_TOOLTIP_POWER"] = "Return the first number raised to the power of the second number.";
|
||||
Blockly.Msg["MATH_ATAN2_HELPURL"] = "https://en.wikipedia.org/wiki/Atan2";
|
||||
Blockly.Msg["MATH_ATAN2_TITLE"] = "atan2 of X:%1 Y:%2";
|
||||
Blockly.Msg["MATH_ATAN2_TOOLTIP"] = "Return the arctangent of point (X, Y) in degrees from -180 to 180.";
|
||||
Blockly.Msg["MATH_CHANGE_HELPURL"] = "https://en.wikipedia.org/wiki/Programming_idiom#Incrementing_a_counter";
|
||||
Blockly.Msg["MATH_CHANGE_TITLE"] = "change %1 by %2";
|
||||
Blockly.Msg["MATH_CHANGE_TOOLTIP"] = "Add a number to variable '%1'.";
|
||||
Blockly.Msg["MATH_CONSTANT_HELPURL"] = "https://en.wikipedia.org/wiki/Mathematical_constant";
|
||||
Blockly.Msg["MATH_CONSTANT_TOOLTIP"] = "Return one of the common constants: π (3.141…), e (2.718…), φ (1.618…), sqrt(2) (1.414…), sqrt(½) (0.707…), or ∞ (infinity).";
|
||||
Blockly.Msg["MATH_CONSTRAIN_HELPURL"] = "https://en.wikipedia.org/wiki/Clamping_(graphics)";
|
||||
Blockly.Msg["MATH_CONSTRAIN_TITLE"] = "constrain %1 low %2 high %3";
|
||||
Blockly.Msg["MATH_CONSTRAIN_TOOLTIP"] = "Constrain a number to be between the specified limits (inclusive).";
|
||||
Blockly.Msg["MATH_DIVISION_SYMBOL"] = "÷";
|
||||
Blockly.Msg["MATH_IS_DIVISIBLE_BY"] = "is divisible by";
|
||||
Blockly.Msg["MATH_IS_EVEN"] = "is even";
|
||||
Blockly.Msg["MATH_IS_NEGATIVE"] = "is negative";
|
||||
Blockly.Msg["MATH_IS_ODD"] = "is odd";
|
||||
Blockly.Msg["MATH_IS_POSITIVE"] = "is positive";
|
||||
Blockly.Msg["MATH_IS_PRIME"] = "is prime";
|
||||
Blockly.Msg["MATH_IS_TOOLTIP"] = "Check if a number is an even, odd, prime, whole, positive, negative, or if it is divisible by certain number. Returns true or false.";
|
||||
Blockly.Msg["MATH_IS_WHOLE"] = "is whole";
|
||||
Blockly.Msg["MATH_MODULO_HELPURL"] = "https://en.wikipedia.org/wiki/Modulo_operation";
|
||||
Blockly.Msg["MATH_MODULO_TITLE"] = "remainder of %1 ÷ %2";
|
||||
Blockly.Msg["MATH_MODULO_TOOLTIP"] = "Return the remainder from dividing the two numbers.";
|
||||
Blockly.Msg["MATH_MULTIPLICATION_SYMBOL"] = "×";
|
||||
Blockly.Msg["MATH_NUMBER_HELPURL"] = "https://en.wikipedia.org/wiki/Number";
|
||||
Blockly.Msg["MATH_NUMBER_TOOLTIP"] = "A number.";
|
||||
Blockly.Msg["MATH_ONLIST_HELPURL"] = "";
|
||||
Blockly.Msg["MATH_ONLIST_OPERATOR_AVERAGE"] = "average of list";
|
||||
Blockly.Msg["MATH_ONLIST_OPERATOR_MAX"] = "max of list";
|
||||
Blockly.Msg["MATH_ONLIST_OPERATOR_MEDIAN"] = "median of list";
|
||||
Blockly.Msg["MATH_ONLIST_OPERATOR_MIN"] = "min of list";
|
||||
Blockly.Msg["MATH_ONLIST_OPERATOR_MODE"] = "modes of list";
|
||||
Blockly.Msg["MATH_ONLIST_OPERATOR_RANDOM"] = "random item of list";
|
||||
Blockly.Msg["MATH_ONLIST_OPERATOR_STD_DEV"] = "standard deviation of list";
|
||||
Blockly.Msg["MATH_ONLIST_OPERATOR_SUM"] = "sum of list";
|
||||
Blockly.Msg["MATH_ONLIST_TOOLTIP_AVERAGE"] = "Return the average (arithmetic mean) of the numeric values in the list.";
|
||||
Blockly.Msg["MATH_ONLIST_TOOLTIP_MAX"] = "Return the largest number in the list.";
|
||||
Blockly.Msg["MATH_ONLIST_TOOLTIP_MEDIAN"] = "Return the median number in the list.";
|
||||
Blockly.Msg["MATH_ONLIST_TOOLTIP_MIN"] = "Return the smallest number in the list.";
|
||||
Blockly.Msg["MATH_ONLIST_TOOLTIP_MODE"] = "Return a list of the most common item(s) in the list.";
|
||||
Blockly.Msg["MATH_ONLIST_TOOLTIP_RANDOM"] = "Return a random element from the list.";
|
||||
Blockly.Msg["MATH_ONLIST_TOOLTIP_STD_DEV"] = "Return the standard deviation of the list.";
|
||||
Blockly.Msg["MATH_ONLIST_TOOLTIP_SUM"] = "Return the sum of all the numbers in the list.";
|
||||
Blockly.Msg["MATH_POWER_SYMBOL"] = "^";
|
||||
Blockly.Msg["MATH_RANDOM_FLOAT_HELPURL"] = "https://en.wikipedia.org/wiki/Random_number_generation";
|
||||
Blockly.Msg["MATH_RANDOM_FLOAT_TITLE_RANDOM"] = "random fraction";
|
||||
Blockly.Msg["MATH_RANDOM_FLOAT_TOOLTIP"] = "Return a random fraction between 0.0 (inclusive) and 1.0 (exclusive).";
|
||||
Blockly.Msg["MATH_RANDOM_INT_HELPURL"] = "https://en.wikipedia.org/wiki/Random_number_generation";
|
||||
Blockly.Msg["MATH_RANDOM_INT_TITLE"] = "random integer from %1 to %2";
|
||||
Blockly.Msg["MATH_RANDOM_INT_TOOLTIP"] = "Return a random integer between the two specified limits, inclusive.";
|
||||
Blockly.Msg["MATH_ROUND_HELPURL"] = "https://en.wikipedia.org/wiki/Rounding";
|
||||
Blockly.Msg["MATH_ROUND_OPERATOR_ROUND"] = "round";
|
||||
Blockly.Msg["MATH_ROUND_OPERATOR_ROUNDDOWN"] = "round down";
|
||||
Blockly.Msg["MATH_ROUND_OPERATOR_ROUNDUP"] = "round up";
|
||||
Blockly.Msg["MATH_ROUND_TOOLTIP"] = "Round a number up or down.";
|
||||
Blockly.Msg["MATH_SINGLE_HELPURL"] = "https://en.wikipedia.org/wiki/Square_root";
|
||||
Blockly.Msg["MATH_SINGLE_OP_ABSOLUTE"] = "absolute";
|
||||
Blockly.Msg["MATH_SINGLE_OP_ROOT"] = "square root";
|
||||
Blockly.Msg["MATH_SINGLE_TOOLTIP_ABS"] = "Return the absolute value of a number.";
|
||||
Blockly.Msg["MATH_SINGLE_TOOLTIP_EXP"] = "Return e to the power of a number.";
|
||||
Blockly.Msg["MATH_SINGLE_TOOLTIP_LN"] = "Return the natural logarithm of a number.";
|
||||
Blockly.Msg["MATH_SINGLE_TOOLTIP_LOG10"] = "Return the base 10 logarithm of a number.";
|
||||
Blockly.Msg["MATH_SINGLE_TOOLTIP_NEG"] = "Return the negation of a number.";
|
||||
Blockly.Msg["MATH_SINGLE_TOOLTIP_POW10"] = "Return 10 to the power of a number.";
|
||||
Blockly.Msg["MATH_SINGLE_TOOLTIP_ROOT"] = "Return the square root of a number.";
|
||||
Blockly.Msg["MATH_SUBTRACTION_SYMBOL"] = "-";
|
||||
Blockly.Msg["MATH_TRIG_ACOS"] = "acos";
|
||||
Blockly.Msg["MATH_TRIG_ASIN"] = "asin";
|
||||
Blockly.Msg["MATH_TRIG_ATAN"] = "atan";
|
||||
Blockly.Msg["MATH_TRIG_COS"] = "cos";
|
||||
Blockly.Msg["MATH_TRIG_HELPURL"] = "https://en.wikipedia.org/wiki/Trigonometric_functions";
|
||||
Blockly.Msg["MATH_TRIG_SIN"] = "sin";
|
||||
Blockly.Msg["MATH_TRIG_TAN"] = "tan";
|
||||
Blockly.Msg["MATH_TRIG_TOOLTIP_ACOS"] = "Return the arccosine of a number.";
|
||||
Blockly.Msg["MATH_TRIG_TOOLTIP_ASIN"] = "Return the arcsine of a number.";
|
||||
Blockly.Msg["MATH_TRIG_TOOLTIP_ATAN"] = "Return the arctangent of a number.";
|
||||
Blockly.Msg["MATH_TRIG_TOOLTIP_COS"] = "Return the cosine of a degree (not radian).";
|
||||
Blockly.Msg["MATH_TRIG_TOOLTIP_SIN"] = "Return the sine of a degree (not radian).";
|
||||
Blockly.Msg["MATH_TRIG_TOOLTIP_TAN"] = "Return the tangent of a degree (not radian).";
|
||||
Blockly.Msg["NEW_COLOUR_VARIABLE"] = "Create colour variable...";
|
||||
Blockly.Msg["NEW_NUMBER_VARIABLE"] = "Create number variable...";
|
||||
Blockly.Msg["NEW_STRING_VARIABLE"] = "Create string variable...";
|
||||
Blockly.Msg["NEW_VARIABLE"] = "Create variable...";
|
||||
Blockly.Msg["NEW_VARIABLE_TITLE"] = "New variable name:";
|
||||
Blockly.Msg["NEW_VARIABLE_TYPE_TITLE"] = "New variable type:";
|
||||
Blockly.Msg["ORDINAL_NUMBER_SUFFIX"] = "";
|
||||
Blockly.Msg["PROCEDURES_ALLOW_STATEMENTS"] = "allow statements";
|
||||
Blockly.Msg["PROCEDURES_BEFORE_PARAMS"] = "with:";
|
||||
Blockly.Msg["PROCEDURES_CALLNORETURN_HELPURL"] = "https://en.wikipedia.org/wiki/Subroutine";
|
||||
Blockly.Msg["PROCEDURES_CALLNORETURN_TOOLTIP"] = "Run the user-defined function '%1'.";
|
||||
Blockly.Msg["PROCEDURES_CALLRETURN_HELPURL"] = "https://en.wikipedia.org/wiki/Subroutine";
|
||||
Blockly.Msg["PROCEDURES_CALLRETURN_TOOLTIP"] = "Run the user-defined function '%1' and use its output.";
|
||||
Blockly.Msg["PROCEDURES_CALL_BEFORE_PARAMS"] = "with:";
|
||||
Blockly.Msg["PROCEDURES_CREATE_DO"] = "Create '%1'";
|
||||
Blockly.Msg["PROCEDURES_DEFNORETURN_COMMENT"] = "Describe this function...";
|
||||
Blockly.Msg["PROCEDURES_DEFNORETURN_DO"] = "";
|
||||
Blockly.Msg["PROCEDURES_DEFNORETURN_HELPURL"] = "https://en.wikipedia.org/wiki/Subroutine";
|
||||
Blockly.Msg["PROCEDURES_DEFNORETURN_PROCEDURE"] = "do something";
|
||||
Blockly.Msg["PROCEDURES_DEFNORETURN_TITLE"] = "to";
|
||||
Blockly.Msg["PROCEDURES_DEFNORETURN_TOOLTIP"] = "Creates a function with no output.";
|
||||
Blockly.Msg["PROCEDURES_DEFRETURN_HELPURL"] = "https://en.wikipedia.org/wiki/Subroutine";
|
||||
Blockly.Msg["PROCEDURES_DEFRETURN_RETURN"] = "return";
|
||||
Blockly.Msg["PROCEDURES_DEFRETURN_TOOLTIP"] = "Creates a function with an output.";
|
||||
Blockly.Msg["PROCEDURES_DEF_DUPLICATE_WARNING"] = "Warning: This function has duplicate parameters.";
|
||||
Blockly.Msg["PROCEDURES_HIGHLIGHT_DEF"] = "Highlight function definition";
|
||||
Blockly.Msg["PROCEDURES_IFRETURN_HELPURL"] = "http://c2.com/cgi/wiki?GuardClause";
|
||||
Blockly.Msg["PROCEDURES_IFRETURN_TOOLTIP"] = "If a value is true, then return a second value.";
|
||||
Blockly.Msg["PROCEDURES_IFRETURN_WARNING"] = "Warning: This block may be used only within a function definition.";
|
||||
Blockly.Msg["PROCEDURES_MUTATORARG_TITLE"] = "input name:";
|
||||
Blockly.Msg["PROCEDURES_MUTATORARG_TOOLTIP"] = "Add an input to the function.";
|
||||
Blockly.Msg["PROCEDURES_MUTATORCONTAINER_TITLE"] = "inputs";
|
||||
Blockly.Msg["PROCEDURES_MUTATORCONTAINER_TOOLTIP"] = "Add, remove, or reorder inputs to this function.";
|
||||
Blockly.Msg["REDO"] = "Redo";
|
||||
Blockly.Msg["REMOVE_COMMENT"] = "Remove Comment";
|
||||
Blockly.Msg["RENAME_VARIABLE"] = "Rename variable...";
|
||||
Blockly.Msg["RENAME_VARIABLE_TITLE"] = "Rename all '%1' variables to:";
|
||||
Blockly.Msg["TEXT_APPEND_HELPURL"] = "https://github.com/google/blockly/wiki/Text#text-modification";
|
||||
Blockly.Msg["TEXT_APPEND_TITLE"] = "to %1 append text %2";
|
||||
Blockly.Msg["TEXT_APPEND_TOOLTIP"] = "Append some text to variable '%1'.";
|
||||
Blockly.Msg["TEXT_CHANGECASE_HELPURL"] = "https://github.com/google/blockly/wiki/Text#adjusting-text-case";
|
||||
Blockly.Msg["TEXT_CHANGECASE_OPERATOR_LOWERCASE"] = "to lower case";
|
||||
Blockly.Msg["TEXT_CHANGECASE_OPERATOR_TITLECASE"] = "to Title Case";
|
||||
Blockly.Msg["TEXT_CHANGECASE_OPERATOR_UPPERCASE"] = "to UPPER CASE";
|
||||
Blockly.Msg["TEXT_CHANGECASE_TOOLTIP"] = "Return a copy of the text in a different case.";
|
||||
Blockly.Msg["TEXT_CHARAT_FIRST"] = "get first letter";
|
||||
Blockly.Msg["TEXT_CHARAT_FROM_END"] = "get letter # from end";
|
||||
Blockly.Msg["TEXT_CHARAT_FROM_START"] = "get letter #";
|
||||
Blockly.Msg["TEXT_CHARAT_HELPURL"] = "https://github.com/google/blockly/wiki/Text#extracting-text";
|
||||
Blockly.Msg["TEXT_CHARAT_LAST"] = "get last letter";
|
||||
Blockly.Msg["TEXT_CHARAT_RANDOM"] = "get random letter";
|
||||
Blockly.Msg["TEXT_CHARAT_TAIL"] = "";
|
||||
Blockly.Msg["TEXT_CHARAT_TITLE"] = "in text %1 %2";
|
||||
Blockly.Msg["TEXT_CHARAT_TOOLTIP"] = "Returns the letter at the specified position.";
|
||||
Blockly.Msg["TEXT_COUNT_HELPURL"] = "https://github.com/google/blockly/wiki/Text#counting-substrings";
|
||||
Blockly.Msg["TEXT_COUNT_MESSAGE0"] = "count %1 in %2";
|
||||
Blockly.Msg["TEXT_COUNT_TOOLTIP"] = "Count how many times some text occurs within some other text.";
|
||||
Blockly.Msg["TEXT_CREATE_JOIN_ITEM_TOOLTIP"] = "Add an item to the text.";
|
||||
Blockly.Msg["TEXT_CREATE_JOIN_TITLE_JOIN"] = "join";
|
||||
Blockly.Msg["TEXT_CREATE_JOIN_TOOLTIP"] = "Add, remove, or reorder sections to reconfigure this text block.";
|
||||
Blockly.Msg["TEXT_GET_SUBSTRING_END_FROM_END"] = "to letter # from end";
|
||||
Blockly.Msg["TEXT_GET_SUBSTRING_END_FROM_START"] = "to letter #";
|
||||
Blockly.Msg["TEXT_GET_SUBSTRING_END_LAST"] = "to last letter";
|
||||
Blockly.Msg["TEXT_GET_SUBSTRING_HELPURL"] = "https://github.com/google/blockly/wiki/Text#extracting-a-region-of-text";
|
||||
Blockly.Msg["TEXT_GET_SUBSTRING_INPUT_IN_TEXT"] = "in text";
|
||||
Blockly.Msg["TEXT_GET_SUBSTRING_START_FIRST"] = "get substring from first letter";
|
||||
Blockly.Msg["TEXT_GET_SUBSTRING_START_FROM_END"] = "get substring from letter # from end";
|
||||
Blockly.Msg["TEXT_GET_SUBSTRING_START_FROM_START"] = "get substring from letter #";
|
||||
Blockly.Msg["TEXT_GET_SUBSTRING_TAIL"] = "";
|
||||
Blockly.Msg["TEXT_GET_SUBSTRING_TOOLTIP"] = "Returns a specified portion of the text.";
|
||||
Blockly.Msg["TEXT_INDEXOF_HELPURL"] = "https://github.com/google/blockly/wiki/Text#finding-text";
|
||||
Blockly.Msg["TEXT_INDEXOF_OPERATOR_FIRST"] = "find first occurrence of text";
|
||||
Blockly.Msg["TEXT_INDEXOF_OPERATOR_LAST"] = "find last occurrence of text";
|
||||
Blockly.Msg["TEXT_INDEXOF_TITLE"] = "in text %1 %2 %3";
|
||||
Blockly.Msg["TEXT_INDEXOF_TOOLTIP"] = "Returns the index of the first/last occurrence of the first text in the second text. Returns %1 if text is not found.";
|
||||
Blockly.Msg["TEXT_ISEMPTY_HELPURL"] = "https://github.com/google/blockly/wiki/Text#checking-for-empty-text";
|
||||
Blockly.Msg["TEXT_ISEMPTY_TITLE"] = "%1 is empty";
|
||||
Blockly.Msg["TEXT_ISEMPTY_TOOLTIP"] = "Returns true if the provided text is empty.";
|
||||
Blockly.Msg["TEXT_JOIN_HELPURL"] = "https://github.com/google/blockly/wiki/Text#text-creation";
|
||||
Blockly.Msg["TEXT_JOIN_TITLE_CREATEWITH"] = "create text with";
|
||||
Blockly.Msg["TEXT_JOIN_TOOLTIP"] = "Create a piece of text by joining together any number of items.";
|
||||
Blockly.Msg["TEXT_LENGTH_HELPURL"] = "https://github.com/google/blockly/wiki/Text#text-modification";
|
||||
Blockly.Msg["TEXT_LENGTH_TITLE"] = "length of %1";
|
||||
Blockly.Msg["TEXT_LENGTH_TOOLTIP"] = "Returns the number of letters (including spaces) in the provided text.";
|
||||
Blockly.Msg["TEXT_PRINT_HELPURL"] = "https://github.com/google/blockly/wiki/Text#printing-text";
|
||||
Blockly.Msg["TEXT_PRINT_TITLE"] = "print %1";
|
||||
Blockly.Msg["TEXT_PRINT_TOOLTIP"] = "Print the specified text, number or other value.";
|
||||
Blockly.Msg["TEXT_PROMPT_HELPURL"] = "https://github.com/google/blockly/wiki/Text#getting-input-from-the-user";
|
||||
Blockly.Msg["TEXT_PROMPT_TOOLTIP_NUMBER"] = "Prompt for user for a number.";
|
||||
Blockly.Msg["TEXT_PROMPT_TOOLTIP_TEXT"] = "Prompt for user for some text.";
|
||||
Blockly.Msg["TEXT_PROMPT_TYPE_NUMBER"] = "prompt for number with message";
|
||||
Blockly.Msg["TEXT_PROMPT_TYPE_TEXT"] = "prompt for text with message";
|
||||
Blockly.Msg["TEXT_REPLACE_HELPURL"] = "https://github.com/google/blockly/wiki/Text#replacing-substrings";
|
||||
Blockly.Msg["TEXT_REPLACE_MESSAGE0"] = "replace %1 with %2 in %3";
|
||||
Blockly.Msg["TEXT_REPLACE_TOOLTIP"] = "Replace all occurances of some text within some other text.";
|
||||
Blockly.Msg["TEXT_REVERSE_HELPURL"] = "https://github.com/google/blockly/wiki/Text#reversing-text";
|
||||
Blockly.Msg["TEXT_REVERSE_MESSAGE0"] = "reverse %1";
|
||||
Blockly.Msg["TEXT_REVERSE_TOOLTIP"] = "Reverses the order of the characters in the text.";
|
||||
Blockly.Msg["TEXT_TEXT_HELPURL"] = "https://en.wikipedia.org/wiki/String_(computer_science)";
|
||||
Blockly.Msg["TEXT_TEXT_TOOLTIP"] = "A letter, word, or line of text.";
|
||||
Blockly.Msg["TEXT_TRIM_HELPURL"] = "https://github.com/google/blockly/wiki/Text#trimming-removing-spaces";
|
||||
Blockly.Msg["TEXT_TRIM_OPERATOR_BOTH"] = "trim spaces from both sides of";
|
||||
Blockly.Msg["TEXT_TRIM_OPERATOR_LEFT"] = "trim spaces from left side of";
|
||||
Blockly.Msg["TEXT_TRIM_OPERATOR_RIGHT"] = "trim spaces from right side of";
|
||||
Blockly.Msg["TEXT_TRIM_TOOLTIP"] = "Return a copy of the text with spaces removed from one or both ends.";
|
||||
Blockly.Msg["TODAY"] = "Today";
|
||||
Blockly.Msg["UNDO"] = "Undo";
|
||||
Blockly.Msg["UNNAMED_KEY"] = "unnamed";
|
||||
Blockly.Msg["VARIABLES_DEFAULT_NAME"] = "item";
|
||||
Blockly.Msg["VARIABLES_GET_CREATE_SET"] = "Create 'set %1'";
|
||||
Blockly.Msg["VARIABLES_GET_HELPURL"] = "https://github.com/google/blockly/wiki/Variables#get";
|
||||
Blockly.Msg["VARIABLES_GET_TOOLTIP"] = "Returns the value of this variable.";
|
||||
Blockly.Msg["VARIABLES_SET"] = "set %1 to %2";
|
||||
Blockly.Msg["VARIABLES_SET_CREATE_GET"] = "Create 'get %1'";
|
||||
Blockly.Msg["VARIABLES_SET_HELPURL"] = "https://github.com/google/blockly/wiki/Variables#set";
|
||||
Blockly.Msg["VARIABLES_SET_TOOLTIP"] = "Sets this variable to be equal to the input.";
|
||||
Blockly.Msg["VARIABLE_ALREADY_EXISTS"] = "A variable named '%1' already exists.";
|
||||
Blockly.Msg["VARIABLE_ALREADY_EXISTS_FOR_ANOTHER_TYPE"] = "A variable named '%1' already exists for another type: '%2'.";
|
||||
Blockly.Msg["WORKSPACE_ARIA_LABEL"] = "Blockly Workspace";
|
||||
Blockly.Msg["WORKSPACE_COMMENT_DEFAULT_TEXT"] = "Say something...";
|
||||
Blockly.Msg["CONTROLS_FOREACH_INPUT_DO"] = Blockly.Msg["CONTROLS_REPEAT_INPUT_DO"];
|
||||
Blockly.Msg["CONTROLS_FOR_INPUT_DO"] = Blockly.Msg["CONTROLS_REPEAT_INPUT_DO"];
|
||||
Blockly.Msg["CONTROLS_IF_ELSEIF_TITLE_ELSEIF"] = Blockly.Msg["CONTROLS_IF_MSG_ELSEIF"];
|
||||
Blockly.Msg["CONTROLS_IF_ELSE_TITLE_ELSE"] = Blockly.Msg["CONTROLS_IF_MSG_ELSE"];
|
||||
Blockly.Msg["CONTROLS_IF_IF_TITLE_IF"] = Blockly.Msg["CONTROLS_IF_MSG_IF"];
|
||||
Blockly.Msg["CONTROLS_IF_MSG_THEN"] = Blockly.Msg["CONTROLS_REPEAT_INPUT_DO"];
|
||||
Blockly.Msg["CONTROLS_WHILEUNTIL_INPUT_DO"] = Blockly.Msg["CONTROLS_REPEAT_INPUT_DO"];
|
||||
Blockly.Msg["LISTS_CREATE_WITH_ITEM_TITLE"] = Blockly.Msg["VARIABLES_DEFAULT_NAME"];
|
||||
Blockly.Msg["LISTS_GET_INDEX_HELPURL"] = Blockly.Msg["LISTS_INDEX_OF_HELPURL"];
|
||||
Blockly.Msg["LISTS_GET_INDEX_INPUT_IN_LIST"] = Blockly.Msg["LISTS_INLIST"];
|
||||
Blockly.Msg["LISTS_GET_SUBLIST_INPUT_IN_LIST"] = Blockly.Msg["LISTS_INLIST"];
|
||||
Blockly.Msg["LISTS_INDEX_OF_INPUT_IN_LIST"] = Blockly.Msg["LISTS_INLIST"];
|
||||
Blockly.Msg["LISTS_SET_INDEX_INPUT_IN_LIST"] = Blockly.Msg["LISTS_INLIST"];
|
||||
Blockly.Msg["MATH_CHANGE_TITLE_ITEM"] = Blockly.Msg["VARIABLES_DEFAULT_NAME"];
|
||||
Blockly.Msg["PROCEDURES_DEFRETURN_COMMENT"] = Blockly.Msg["PROCEDURES_DEFNORETURN_COMMENT"];
|
||||
Blockly.Msg["PROCEDURES_DEFRETURN_DO"] = Blockly.Msg["PROCEDURES_DEFNORETURN_DO"];
|
||||
Blockly.Msg["PROCEDURES_DEFRETURN_PROCEDURE"] = Blockly.Msg["PROCEDURES_DEFNORETURN_PROCEDURE"];
|
||||
Blockly.Msg["PROCEDURES_DEFRETURN_TITLE"] = Blockly.Msg["PROCEDURES_DEFNORETURN_TITLE"];
|
||||
Blockly.Msg["TEXT_APPEND_VARIABLE"] = Blockly.Msg["VARIABLES_DEFAULT_NAME"];
|
||||
Blockly.Msg["TEXT_CREATE_JOIN_ITEM_TITLE_ITEM"] = Blockly.Msg["VARIABLES_DEFAULT_NAME"];
|
||||
|
||||
Blockly.Msg["MATH_HUE"] = "230";
|
||||
Blockly.Msg["LOOPS_HUE"] = "120";
|
||||
Blockly.Msg["LISTS_HUE"] = "260";
|
||||
Blockly.Msg["LOGIC_HUE"] = "210";
|
||||
Blockly.Msg["VARIABLES_HUE"] = "330";
|
||||
Blockly.Msg["TEXTS_HUE"] = "160";
|
||||
Blockly.Msg["PROCEDURES_HUE"] = "290";
|
||||
Blockly.Msg["COLOUR_HUE"] = "20";
|
||||
Blockly.Msg["VARIABLES_DYNAMIC_HUE"] = "310";
|
||||
98
clover_blocks/www/blockly/python_compressed.js
Executable file
@@ -0,0 +1,98 @@
|
||||
// Do not edit this file; automatically generated by gulp.
|
||||
|
||||
/* eslint-disable */
|
||||
;(function(root, factory) {
|
||||
if (typeof define === 'function' && define.amd) { // AMD
|
||||
define(['./blockly_compressed.js'], factory);
|
||||
} else if (typeof exports === 'object') { // Node.js
|
||||
module.exports = factory(require('./blockly_compressed.js'));
|
||||
} else { // Browser
|
||||
root.Blockly.Python = factory(root.Blockly);
|
||||
}
|
||||
}(this, function(Blockly) {
|
||||
'use strict';Blockly.Python=new Blockly.Generator("Python");Blockly.Python.addReservedWords("False,None,True,and,as,assert,break,class,continue,def,del,elif,else,except,exec,finally,for,from,global,if,import,in,is,lambda,nonlocal,not,or,pass,print,raise,return,try,while,with,yield,NotImplemented,Ellipsis,__debug__,quit,exit,copyright,license,credits,ArithmeticError,AssertionError,AttributeError,BaseException,BlockingIOError,BrokenPipeError,BufferError,BytesWarning,ChildProcessError,ConnectionAbortedError,ConnectionError,ConnectionRefusedError,ConnectionResetError,DeprecationWarning,EOFError,Ellipsis,EnvironmentError,Exception,FileExistsError,FileNotFoundError,FloatingPointError,FutureWarning,GeneratorExit,IOError,ImportError,ImportWarning,IndentationError,IndexError,InterruptedError,IsADirectoryError,KeyError,KeyboardInterrupt,LookupError,MemoryError,ModuleNotFoundError,NameError,NotADirectoryError,NotImplemented,NotImplementedError,OSError,OverflowError,PendingDeprecationWarning,PermissionError,ProcessLookupError,RecursionError,ReferenceError,ResourceWarning,RuntimeError,RuntimeWarning,StandardError,StopAsyncIteration,StopIteration,SyntaxError,SyntaxWarning,SystemError,SystemExit,TabError,TimeoutError,TypeError,UnboundLocalError,UnicodeDecodeError,UnicodeEncodeError,UnicodeError,UnicodeTranslateError,UnicodeWarning,UserWarning,ValueError,Warning,ZeroDivisionError,_,__build_class__,__debug__,__doc__,__import__,__loader__,__name__,__package__,__spec__,abs,all,any,apply,ascii,basestring,bin,bool,buffer,bytearray,bytes,callable,chr,classmethod,cmp,coerce,compile,complex,copyright,credits,delattr,dict,dir,divmod,enumerate,eval,exec,execfile,exit,file,filter,float,format,frozenset,getattr,globals,hasattr,hash,help,hex,id,input,int,intern,isinstance,issubclass,iter,len,license,list,locals,long,map,max,memoryview,min,next,object,oct,open,ord,pow,print,property,quit,range,raw_input,reduce,reload,repr,reversed,round,set,setattr,slice,sorted,staticmethod,str,sum,super,tuple,type,unichr,unicode,vars,xrange,zip");
|
||||
Blockly.Python.ORDER_ATOMIC=0;Blockly.Python.ORDER_COLLECTION=1;Blockly.Python.ORDER_STRING_CONVERSION=1;Blockly.Python.ORDER_MEMBER=2.1;Blockly.Python.ORDER_FUNCTION_CALL=2.2;Blockly.Python.ORDER_EXPONENTIATION=3;Blockly.Python.ORDER_UNARY_SIGN=4;Blockly.Python.ORDER_BITWISE_NOT=4;Blockly.Python.ORDER_MULTIPLICATIVE=5;Blockly.Python.ORDER_ADDITIVE=6;Blockly.Python.ORDER_BITWISE_SHIFT=7;Blockly.Python.ORDER_BITWISE_AND=8;Blockly.Python.ORDER_BITWISE_XOR=9;Blockly.Python.ORDER_BITWISE_OR=10;
|
||||
Blockly.Python.ORDER_RELATIONAL=11;Blockly.Python.ORDER_LOGICAL_NOT=12;Blockly.Python.ORDER_LOGICAL_AND=13;Blockly.Python.ORDER_LOGICAL_OR=14;Blockly.Python.ORDER_CONDITIONAL=15;Blockly.Python.ORDER_LAMBDA=16;Blockly.Python.ORDER_NONE=99;
|
||||
Blockly.Python.ORDER_OVERRIDES=[[Blockly.Python.ORDER_FUNCTION_CALL,Blockly.Python.ORDER_MEMBER],[Blockly.Python.ORDER_FUNCTION_CALL,Blockly.Python.ORDER_FUNCTION_CALL],[Blockly.Python.ORDER_MEMBER,Blockly.Python.ORDER_MEMBER],[Blockly.Python.ORDER_MEMBER,Blockly.Python.ORDER_FUNCTION_CALL],[Blockly.Python.ORDER_LOGICAL_NOT,Blockly.Python.ORDER_LOGICAL_NOT],[Blockly.Python.ORDER_LOGICAL_AND,Blockly.Python.ORDER_LOGICAL_AND],[Blockly.Python.ORDER_LOGICAL_OR,Blockly.Python.ORDER_LOGICAL_OR]];
|
||||
Blockly.Python.init=function(a){Blockly.Python.PASS=this.INDENT+"pass\n";Blockly.Python.definitions_=Object.create(null);Blockly.Python.functionNames_=Object.create(null);Blockly.Python.variableDB_?Blockly.Python.variableDB_.reset():Blockly.Python.variableDB_=new Blockly.Names(Blockly.Python.RESERVED_WORDS_);Blockly.Python.variableDB_.setVariableMap(a.getVariableMap());for(var b=[],c=Blockly.Variables.allDeveloperVariables(a),d=0;d<c.length;d++)b.push(Blockly.Python.variableDB_.getName(c[d],Blockly.Names.DEVELOPER_VARIABLE_TYPE)+
|
||||
" = None");a=Blockly.Variables.allUsedVarModels(a);for(d=0;d<a.length;d++)b.push(Blockly.Python.variableDB_.getName(a[d].getId(),Blockly.VARIABLE_CATEGORY_NAME)+" = None");Blockly.Python.definitions_.variables=b.join("\n")};
|
||||
Blockly.Python.finish=function(a){var b=[],c=[],d;for(d in Blockly.Python.definitions_){var e=Blockly.Python.definitions_[d];e.match(/^(from\s+\S+\s+)?import\s+\S+/)?b.push(e):c.push(e)}delete Blockly.Python.definitions_;delete Blockly.Python.functionNames_;Blockly.Python.variableDB_.reset();return(b.join("\n")+"\n\n"+c.join("\n\n")).replace(/\n\n+/g,"\n\n").replace(/\n*$/,"\n\n\n")+a};Blockly.Python.scrubNakedValue=function(a){return a+"\n"};
|
||||
Blockly.Python.quote_=function(a){a=a.replace(/\\/g,"\\\\").replace(/\n/g,"\\\n");var b="'";-1!==a.indexOf("'")&&(-1===a.indexOf('"')?b='"':a=a.replace(/'/g,"\\'"));return b+a+b};Blockly.Python.multiline_quote_=function(a){a=a.replace(/'''/g,"\\'\\'\\'");return"'''"+a+"'''"};
|
||||
Blockly.Python.scrub_=function(a,b,c){var d="";if(!a.outputConnection||!a.outputConnection.targetConnection){var e=a.getCommentText();e&&(e=Blockly.utils.string.wrap(e,Blockly.Python.COMMENT_WRAP-3),d+=Blockly.Python.prefixLines(e+"\n","# "));for(var f=0;f<a.inputList.length;f++)a.inputList[f].type==Blockly.INPUT_VALUE&&(e=a.inputList[f].connection.targetBlock())&&(e=Blockly.Python.allNestedComments(e))&&(d+=Blockly.Python.prefixLines(e,"# "))}a=a.nextConnection&&a.nextConnection.targetBlock();c=
|
||||
c?"":Blockly.Python.blockToCode(a);return d+b+c};Blockly.Python.getAdjustedInt=function(a,b,c,d){c=c||0;a.workspace.options.oneBasedIndex&&c--;var e=a.workspace.options.oneBasedIndex?"1":"0";a=Blockly.Python.valueToCode(a,b,c?Blockly.Python.ORDER_ADDITIVE:Blockly.Python.ORDER_NONE)||e;Blockly.isNumber(a)?(a=parseInt(a,10)+c,d&&(a=-a)):(a=0<c?"int("+a+" + "+c+")":0>c?"int("+a+" - "+-c+")":"int("+a+")",d&&(a="-"+a));return a};Blockly.Python.colour={};Blockly.Python.colour_picker=function(a){return[Blockly.Python.quote_(a.getFieldValue("COLOUR")),Blockly.Python.ORDER_ATOMIC]};Blockly.Python.colour_random=function(a){Blockly.Python.definitions_.import_random="import random";return["'#%06x' % random.randint(0, 2**24 - 1)",Blockly.Python.ORDER_FUNCTION_CALL]};
|
||||
Blockly.Python.colour_rgb=function(a){var b=Blockly.Python.provideFunction_("colour_rgb",["def "+Blockly.Python.FUNCTION_NAME_PLACEHOLDER_+"(r, g, b):"," r = round(min(100, max(0, r)) * 2.55)"," g = round(min(100, max(0, g)) * 2.55)"," b = round(min(100, max(0, b)) * 2.55)"," return '#%02x%02x%02x' % (r, g, b)"]),c=Blockly.Python.valueToCode(a,"RED",Blockly.Python.ORDER_NONE)||0,d=Blockly.Python.valueToCode(a,"GREEN",Blockly.Python.ORDER_NONE)||0;a=Blockly.Python.valueToCode(a,"BLUE",Blockly.Python.ORDER_NONE)||
|
||||
0;return[b+"("+c+", "+d+", "+a+")",Blockly.Python.ORDER_FUNCTION_CALL]};
|
||||
Blockly.Python.colour_blend=function(a){var b=Blockly.Python.provideFunction_("colour_blend",["def "+Blockly.Python.FUNCTION_NAME_PLACEHOLDER_+"(colour1, colour2, ratio):"," r1, r2 = int(colour1[1:3], 16), int(colour2[1:3], 16)"," g1, g2 = int(colour1[3:5], 16), int(colour2[3:5], 16)"," b1, b2 = int(colour1[5:7], 16), int(colour2[5:7], 16)"," ratio = min(1, max(0, ratio))"," r = round(r1 * (1 - ratio) + r2 * ratio)"," g = round(g1 * (1 - ratio) + g2 * ratio)"," b = round(b1 * (1 - ratio) + b2 * ratio)",
|
||||
" return '#%02x%02x%02x' % (r, g, b)"]),c=Blockly.Python.valueToCode(a,"COLOUR1",Blockly.Python.ORDER_NONE)||"'#000000'",d=Blockly.Python.valueToCode(a,"COLOUR2",Blockly.Python.ORDER_NONE)||"'#000000'";a=Blockly.Python.valueToCode(a,"RATIO",Blockly.Python.ORDER_NONE)||0;return[b+"("+c+", "+d+", "+a+")",Blockly.Python.ORDER_FUNCTION_CALL]};Blockly.Python.lists={};Blockly.Python.lists_create_empty=function(a){return["[]",Blockly.Python.ORDER_ATOMIC]};Blockly.Python.lists_create_with=function(a){for(var b=Array(a.itemCount_),c=0;c<a.itemCount_;c++)b[c]=Blockly.Python.valueToCode(a,"ADD"+c,Blockly.Python.ORDER_NONE)||"None";return["["+b.join(", ")+"]",Blockly.Python.ORDER_ATOMIC]};
|
||||
Blockly.Python.lists_repeat=function(a){var b=Blockly.Python.valueToCode(a,"ITEM",Blockly.Python.ORDER_NONE)||"None";a=Blockly.Python.valueToCode(a,"NUM",Blockly.Python.ORDER_MULTIPLICATIVE)||"0";return["["+b+"] * "+a,Blockly.Python.ORDER_MULTIPLICATIVE]};Blockly.Python.lists_length=function(a){return["len("+(Blockly.Python.valueToCode(a,"VALUE",Blockly.Python.ORDER_NONE)||"[]")+")",Blockly.Python.ORDER_FUNCTION_CALL]};
|
||||
Blockly.Python.lists_isEmpty=function(a){return["not len("+(Blockly.Python.valueToCode(a,"VALUE",Blockly.Python.ORDER_NONE)||"[]")+")",Blockly.Python.ORDER_LOGICAL_NOT]};
|
||||
Blockly.Python.lists_indexOf=function(a){var b=Blockly.Python.valueToCode(a,"FIND",Blockly.Python.ORDER_NONE)||"[]",c=Blockly.Python.valueToCode(a,"VALUE",Blockly.Python.ORDER_NONE)||"''";if(a.workspace.options.oneBasedIndex)var d=" 0",e=" + 1",f="";else d=" -1",e="",f=" - 1";if("FIRST"==a.getFieldValue("END"))return a=Blockly.Python.provideFunction_("first_index",["def "+Blockly.Python.FUNCTION_NAME_PLACEHOLDER_+"(my_list, elem):"," try: index = my_list.index(elem)"+e," except: index ="+d," return index"]),
|
||||
[a+"("+c+", "+b+")",Blockly.Python.ORDER_FUNCTION_CALL];a=Blockly.Python.provideFunction_("last_index",["def "+Blockly.Python.FUNCTION_NAME_PLACEHOLDER_+"(my_list, elem):"," try: index = len(my_list) - my_list[::-1].index(elem)"+f," except: index ="+d," return index"]);return[a+"("+c+", "+b+")",Blockly.Python.ORDER_FUNCTION_CALL]};
|
||||
Blockly.Python.lists_getIndex=function(a){var b=a.getFieldValue("MODE")||"GET",c=a.getFieldValue("WHERE")||"FROM_START",d=Blockly.Python.valueToCode(a,"VALUE","RANDOM"==c?Blockly.Python.ORDER_NONE:Blockly.Python.ORDER_MEMBER)||"[]";switch(c){case "FIRST":if("GET"==b)return[d+"[0]",Blockly.Python.ORDER_MEMBER];if("GET_REMOVE"==b)return[d+".pop(0)",Blockly.Python.ORDER_FUNCTION_CALL];if("REMOVE"==b)return d+".pop(0)\n";break;case "LAST":if("GET"==b)return[d+"[-1]",Blockly.Python.ORDER_MEMBER];if("GET_REMOVE"==
|
||||
b)return[d+".pop()",Blockly.Python.ORDER_FUNCTION_CALL];if("REMOVE"==b)return d+".pop()\n";break;case "FROM_START":a=Blockly.Python.getAdjustedInt(a,"AT");if("GET"==b)return[d+"["+a+"]",Blockly.Python.ORDER_MEMBER];if("GET_REMOVE"==b)return[d+".pop("+a+")",Blockly.Python.ORDER_FUNCTION_CALL];if("REMOVE"==b)return d+".pop("+a+")\n";break;case "FROM_END":a=Blockly.Python.getAdjustedInt(a,"AT",1,!0);if("GET"==b)return[d+"["+a+"]",Blockly.Python.ORDER_MEMBER];if("GET_REMOVE"==b)return[d+".pop("+a+")",
|
||||
Blockly.Python.ORDER_FUNCTION_CALL];if("REMOVE"==b)return d+".pop("+a+")\n";break;case "RANDOM":Blockly.Python.definitions_.import_random="import random";if("GET"==b)return["random.choice("+d+")",Blockly.Python.ORDER_FUNCTION_CALL];d=Blockly.Python.provideFunction_("lists_remove_random_item",["def "+Blockly.Python.FUNCTION_NAME_PLACEHOLDER_+"(myList):"," x = int(random.random() * len(myList))"," return myList.pop(x)"])+"("+d+")";if("GET_REMOVE"==b)return[d,Blockly.Python.ORDER_FUNCTION_CALL];if("REMOVE"==
|
||||
b)return d+"\n"}throw Error("Unhandled combination (lists_getIndex).");};
|
||||
Blockly.Python.lists_setIndex=function(a){var b=Blockly.Python.valueToCode(a,"LIST",Blockly.Python.ORDER_MEMBER)||"[]",c=a.getFieldValue("MODE")||"GET",d=a.getFieldValue("WHERE")||"FROM_START",e=Blockly.Python.valueToCode(a,"TO",Blockly.Python.ORDER_NONE)||"None";switch(d){case "FIRST":if("SET"==c)return b+"[0] = "+e+"\n";if("INSERT"==c)return b+".insert(0, "+e+")\n";break;case "LAST":if("SET"==c)return b+"[-1] = "+e+"\n";if("INSERT"==c)return b+".append("+e+")\n";break;case "FROM_START":a=Blockly.Python.getAdjustedInt(a,
|
||||
"AT");if("SET"==c)return b+"["+a+"] = "+e+"\n";if("INSERT"==c)return b+".insert("+a+", "+e+")\n";break;case "FROM_END":a=Blockly.Python.getAdjustedInt(a,"AT",1,!0);if("SET"==c)return b+"["+a+"] = "+e+"\n";if("INSERT"==c)return b+".insert("+a+", "+e+")\n";break;case "RANDOM":Blockly.Python.definitions_.import_random="import random";b.match(/^\w+$/)?a="":(a=Blockly.Python.variableDB_.getDistinctName("tmp_list",Blockly.VARIABLE_CATEGORY_NAME),d=a+" = "+b+"\n",b=a,a=d);d=Blockly.Python.variableDB_.getDistinctName("tmp_x",
|
||||
Blockly.VARIABLE_CATEGORY_NAME);a+=d+" = int(random.random() * len("+b+"))\n";if("SET"==c)return a+(b+"["+d+"] = "+e+"\n");if("INSERT"==c)return a+(b+".insert("+d+", "+e+")\n")}throw Error("Unhandled combination (lists_setIndex).");};
|
||||
Blockly.Python.lists_getSublist=function(a){var b=Blockly.Python.valueToCode(a,"LIST",Blockly.Python.ORDER_MEMBER)||"[]",c=a.getFieldValue("WHERE1"),d=a.getFieldValue("WHERE2");switch(c){case "FROM_START":c=Blockly.Python.getAdjustedInt(a,"AT1");"0"==c&&(c="");break;case "FROM_END":c=Blockly.Python.getAdjustedInt(a,"AT1",1,!0);break;case "FIRST":c="";break;default:throw Error("Unhandled option (lists_getSublist)");}switch(d){case "FROM_START":a=Blockly.Python.getAdjustedInt(a,"AT2",1);break;case "FROM_END":a=
|
||||
Blockly.Python.getAdjustedInt(a,"AT2",0,!0);Blockly.isNumber(String(a))?"0"==a&&(a=""):(Blockly.Python.definitions_.import_sys="import sys",a+=" or sys.maxsize");break;case "LAST":a="";break;default:throw Error("Unhandled option (lists_getSublist)");}return[b+"["+c+" : "+a+"]",Blockly.Python.ORDER_MEMBER]};
|
||||
Blockly.Python.lists_sort=function(a){var b=Blockly.Python.valueToCode(a,"LIST",Blockly.Python.ORDER_NONE)||"[]",c=a.getFieldValue("TYPE");a="1"===a.getFieldValue("DIRECTION")?"False":"True";return[Blockly.Python.provideFunction_("lists_sort",["def "+Blockly.Python.FUNCTION_NAME_PLACEHOLDER_+"(my_list, type, reverse):"," def try_float(s):"," try:"," return float(s)"," except:"," return 0"," key_funcs = {",' "NUMERIC": try_float,',' "TEXT": str,',' "IGNORE_CASE": lambda s: str(s).lower()',
|
||||
" }"," key_func = key_funcs[type]"," list_cpy = list(my_list)"," return sorted(list_cpy, key=key_func, reverse=reverse)"])+"("+b+', "'+c+'", '+a+")",Blockly.Python.ORDER_FUNCTION_CALL]};
|
||||
Blockly.Python.lists_split=function(a){var b=a.getFieldValue("MODE");if("SPLIT"==b)b=Blockly.Python.valueToCode(a,"INPUT",Blockly.Python.ORDER_MEMBER)||"''",a=Blockly.Python.valueToCode(a,"DELIM",Blockly.Python.ORDER_NONE),a=b+".split("+a+")";else if("JOIN"==b)b=Blockly.Python.valueToCode(a,"INPUT",Blockly.Python.ORDER_NONE)||"[]",a=Blockly.Python.valueToCode(a,"DELIM",Blockly.Python.ORDER_MEMBER)||"''",a=a+".join("+b+")";else throw Error("Unknown mode: "+b);return[a,Blockly.Python.ORDER_FUNCTION_CALL]};
|
||||
Blockly.Python.lists_reverse=function(a){return["list(reversed("+(Blockly.Python.valueToCode(a,"LIST",Blockly.Python.ORDER_NONE)||"[]")+"))",Blockly.Python.ORDER_FUNCTION_CALL]};Blockly.Python.logic={};
|
||||
Blockly.Python.controls_if=function(a){var b=0,c="";Blockly.Python.STATEMENT_PREFIX&&(c+=Blockly.Python.injectId(Blockly.Python.STATEMENT_PREFIX,a));do{var d=Blockly.Python.valueToCode(a,"IF"+b,Blockly.Python.ORDER_NONE)||"False";var e=Blockly.Python.statementToCode(a,"DO"+b)||Blockly.Python.PASS;Blockly.Python.STATEMENT_SUFFIX&&(e=Blockly.Python.prefixLines(Blockly.Python.injectId(Blockly.Python.STATEMENT_SUFFIX,a),Blockly.Python.INDENT)+e);c+=(0==b?"if ":"elif ")+d+":\n"+e;++b}while(a.getInput("IF"+
|
||||
b));if(a.getInput("ELSE")||Blockly.Python.STATEMENT_SUFFIX)e=Blockly.Python.statementToCode(a,"ELSE")||Blockly.Python.PASS,Blockly.Python.STATEMENT_SUFFIX&&(e=Blockly.Python.prefixLines(Blockly.Python.injectId(Blockly.Python.STATEMENT_SUFFIX,a),Blockly.Python.INDENT)+e),c+="else:\n"+e;return c};Blockly.Python.controls_ifelse=Blockly.Python.controls_if;
|
||||
Blockly.Python.logic_compare=function(a){var b={EQ:"==",NEQ:"!=",LT:"<",LTE:"<=",GT:">",GTE:">="}[a.getFieldValue("OP")],c=Blockly.Python.ORDER_RELATIONAL,d=Blockly.Python.valueToCode(a,"A",c)||"0";a=Blockly.Python.valueToCode(a,"B",c)||"0";return[d+" "+b+" "+a,c]};
|
||||
Blockly.Python.logic_operation=function(a){var b="AND"==a.getFieldValue("OP")?"and":"or",c="and"==b?Blockly.Python.ORDER_LOGICAL_AND:Blockly.Python.ORDER_LOGICAL_OR,d=Blockly.Python.valueToCode(a,"A",c);a=Blockly.Python.valueToCode(a,"B",c);if(d||a){var e="and"==b?"True":"False";d||(d=e);a||(a=e)}else a=d="False";return[d+" "+b+" "+a,c]};Blockly.Python.logic_negate=function(a){return["not "+(Blockly.Python.valueToCode(a,"BOOL",Blockly.Python.ORDER_LOGICAL_NOT)||"True"),Blockly.Python.ORDER_LOGICAL_NOT]};
|
||||
Blockly.Python.logic_boolean=function(a){return["TRUE"==a.getFieldValue("BOOL")?"True":"False",Blockly.Python.ORDER_ATOMIC]};Blockly.Python.logic_null=function(a){return["None",Blockly.Python.ORDER_ATOMIC]};
|
||||
Blockly.Python.logic_ternary=function(a){var b=Blockly.Python.valueToCode(a,"IF",Blockly.Python.ORDER_CONDITIONAL)||"False",c=Blockly.Python.valueToCode(a,"THEN",Blockly.Python.ORDER_CONDITIONAL)||"None";a=Blockly.Python.valueToCode(a,"ELSE",Blockly.Python.ORDER_CONDITIONAL)||"None";return[c+" if "+b+" else "+a,Blockly.Python.ORDER_CONDITIONAL]};Blockly.Python.loops={};Blockly.Python.controls_repeat_ext=function(a){var b=a.getField("TIMES")?String(parseInt(a.getFieldValue("TIMES"),10)):Blockly.Python.valueToCode(a,"TIMES",Blockly.Python.ORDER_NONE)||"0";b=Blockly.isNumber(b)?parseInt(b,10):"int("+b+")";var c=Blockly.Python.statementToCode(a,"DO");c=Blockly.Python.addLoopTrap(c,a)||Blockly.Python.PASS;return"for "+Blockly.Python.variableDB_.getDistinctName("count",Blockly.VARIABLE_CATEGORY_NAME)+" in range("+b+"):\n"+c};
|
||||
Blockly.Python.controls_repeat=Blockly.Python.controls_repeat_ext;Blockly.Python.controls_whileUntil=function(a){var b="UNTIL"==a.getFieldValue("MODE"),c=Blockly.Python.valueToCode(a,"BOOL",b?Blockly.Python.ORDER_LOGICAL_NOT:Blockly.Python.ORDER_NONE)||"False",d=Blockly.Python.statementToCode(a,"DO");d=Blockly.Python.addLoopTrap(d,a)||Blockly.Python.PASS;b&&(c="not "+c);return"while "+c+":\n"+d};
|
||||
Blockly.Python.controls_for=function(a){var b=Blockly.Python.variableDB_.getName(a.getFieldValue("VAR"),Blockly.VARIABLE_CATEGORY_NAME),c=Blockly.Python.valueToCode(a,"FROM",Blockly.Python.ORDER_NONE)||"0",d=Blockly.Python.valueToCode(a,"TO",Blockly.Python.ORDER_NONE)||"0",e=Blockly.Python.valueToCode(a,"BY",Blockly.Python.ORDER_NONE)||"1",f=Blockly.Python.statementToCode(a,"DO");f=Blockly.Python.addLoopTrap(f,a)||Blockly.Python.PASS;var l="",h=function(){return Blockly.Python.provideFunction_("upRange",
|
||||
["def "+Blockly.Python.FUNCTION_NAME_PLACEHOLDER_+"(start, stop, step):"," while start <= stop:"," yield start"," start += abs(step)"])},g=function(){return Blockly.Python.provideFunction_("downRange",["def "+Blockly.Python.FUNCTION_NAME_PLACEHOLDER_+"(start, stop, step):"," while start >= stop:"," yield start"," start -= abs(step)"])};a=function(a,b,c){return"("+a+" <= "+b+") and "+h()+"("+a+", "+b+", "+c+") or "+g()+"("+a+", "+b+", "+c+")"};if(Blockly.isNumber(c)&&Blockly.isNumber(d)&&
|
||||
Blockly.isNumber(e))c=Number(c),d=Number(d),e=Math.abs(Number(e)),0===c%1&&0===d%1&&0===e%1?(c<=d?(d++,a=0==c&&1==e?d:c+", "+d,1!=e&&(a+=", "+e)):(d--,a=c+", "+d+", -"+e),a="range("+a+")"):(a=c<d?h():g(),a+="("+c+", "+d+", "+e+")");else{var k=function(a,c){Blockly.isNumber(a)?a=Number(a):a.match(/^\w+$/)?a="float("+a+")":(c=Blockly.Python.variableDB_.getDistinctName(b+c,Blockly.VARIABLE_CATEGORY_NAME),l+=c+" = float("+a+")\n",a=c);return a};c=k(c,"_start");d=k(d,"_end");k(e,"_inc");a="number"==typeof c&&
|
||||
"number"==typeof d?c<d?h(c,d,e):g(c,d,e):a(c,d,e)}return l+="for "+b+" in "+a+":\n"+f};Blockly.Python.controls_forEach=function(a){var b=Blockly.Python.variableDB_.getName(a.getFieldValue("VAR"),Blockly.VARIABLE_CATEGORY_NAME),c=Blockly.Python.valueToCode(a,"LIST",Blockly.Python.ORDER_RELATIONAL)||"[]",d=Blockly.Python.statementToCode(a,"DO");d=Blockly.Python.addLoopTrap(d,a)||Blockly.Python.PASS;return"for "+b+" in "+c+":\n"+d};
|
||||
Blockly.Python.controls_flow_statements=function(a){var b="";Blockly.Python.STATEMENT_PREFIX&&(b+=Blockly.Python.injectId(Blockly.Python.STATEMENT_PREFIX,a));Blockly.Python.STATEMENT_SUFFIX&&(b+=Blockly.Python.injectId(Blockly.Python.STATEMENT_SUFFIX,a));if(Blockly.Python.STATEMENT_PREFIX){var c=Blockly.Constants.Loops.CONTROL_FLOW_IN_LOOP_CHECK_MIXIN.getSurroundLoop(a);c&&!c.suppressPrefixSuffix&&(b+=Blockly.Python.injectId(Blockly.Python.STATEMENT_PREFIX,c))}switch(a.getFieldValue("FLOW")){case "BREAK":return b+
|
||||
"break\n";case "CONTINUE":return b+"continue\n"}throw Error("Unknown flow statement.");};Blockly.Python.math={};Blockly.Python.addReservedWords("math,random,Number");Blockly.Python.math_number=function(a){a=Number(a.getFieldValue("NUM"));if(Infinity==a){a='float("inf")';var b=Blockly.Python.ORDER_FUNCTION_CALL}else-Infinity==a?(a='-float("inf")',b=Blockly.Python.ORDER_UNARY_SIGN):b=0>a?Blockly.Python.ORDER_UNARY_SIGN:Blockly.Python.ORDER_ATOMIC;return[a,b]};
|
||||
Blockly.Python.math_arithmetic=function(a){var b={ADD:[" + ",Blockly.Python.ORDER_ADDITIVE],MINUS:[" - ",Blockly.Python.ORDER_ADDITIVE],MULTIPLY:[" * ",Blockly.Python.ORDER_MULTIPLICATIVE],DIVIDE:[" / ",Blockly.Python.ORDER_MULTIPLICATIVE],POWER:[" ** ",Blockly.Python.ORDER_EXPONENTIATION]}[a.getFieldValue("OP")],c=b[0];b=b[1];var d=Blockly.Python.valueToCode(a,"A",b)||"0";a=Blockly.Python.valueToCode(a,"B",b)||"0";return[d+c+a,b]};
|
||||
Blockly.Python.math_single=function(a){var b=a.getFieldValue("OP");if("NEG"==b){var c=Blockly.Python.valueToCode(a,"NUM",Blockly.Python.ORDER_UNARY_SIGN)||"0";return["-"+c,Blockly.Python.ORDER_UNARY_SIGN]}Blockly.Python.definitions_.import_math="import math";a="SIN"==b||"COS"==b||"TAN"==b?Blockly.Python.valueToCode(a,"NUM",Blockly.Python.ORDER_MULTIPLICATIVE)||"0":Blockly.Python.valueToCode(a,"NUM",Blockly.Python.ORDER_NONE)||"0";switch(b){case "ABS":c="math.fabs("+a+")";break;case "ROOT":c="math.sqrt("+
|
||||
a+")";break;case "LN":c="math.log("+a+")";break;case "LOG10":c="math.log10("+a+")";break;case "EXP":c="math.exp("+a+")";break;case "POW10":c="math.pow(10,"+a+")";break;case "ROUND":c="round("+a+")";break;case "ROUNDUP":c="math.ceil("+a+")";break;case "ROUNDDOWN":c="math.floor("+a+")";break;case "SIN":c="math.sin("+a+" / 180.0 * math.pi)";break;case "COS":c="math.cos("+a+" / 180.0 * math.pi)";break;case "TAN":c="math.tan("+a+" / 180.0 * math.pi)"}if(c)return[c,Blockly.Python.ORDER_FUNCTION_CALL];switch(b){case "ASIN":c=
|
||||
"math.asin("+a+") / math.pi * 180";break;case "ACOS":c="math.acos("+a+") / math.pi * 180";break;case "ATAN":c="math.atan("+a+") / math.pi * 180";break;default:throw Error("Unknown math operator: "+b);}return[c,Blockly.Python.ORDER_MULTIPLICATIVE]};
|
||||
Blockly.Python.math_constant=function(a){var b={PI:["math.pi",Blockly.Python.ORDER_MEMBER],E:["math.e",Blockly.Python.ORDER_MEMBER],GOLDEN_RATIO:["(1 + math.sqrt(5)) / 2",Blockly.Python.ORDER_MULTIPLICATIVE],SQRT2:["math.sqrt(2)",Blockly.Python.ORDER_MEMBER],SQRT1_2:["math.sqrt(1.0 / 2)",Blockly.Python.ORDER_MEMBER],INFINITY:["float('inf')",Blockly.Python.ORDER_ATOMIC]};a=a.getFieldValue("CONSTANT");"INFINITY"!=a&&(Blockly.Python.definitions_.import_math="import math");return b[a]};
|
||||
Blockly.Python.math_number_property=function(a){var b=Blockly.Python.valueToCode(a,"NUMBER_TO_CHECK",Blockly.Python.ORDER_MULTIPLICATIVE)||"0",c=a.getFieldValue("PROPERTY");if("PRIME"==c)return Blockly.Python.definitions_.import_math="import math",Blockly.Python.definitions_.from_numbers_import_Number="from numbers import Number",[Blockly.Python.provideFunction_("math_isPrime",["def "+Blockly.Python.FUNCTION_NAME_PLACEHOLDER_+"(n):"," # https://en.wikipedia.org/wiki/Primality_test#Naive_methods",
|
||||
" # If n is not a number but a string, try parsing it."," if not isinstance(n, Number):"," try:"," n = float(n)"," except:"," return False"," if n == 2 or n == 3:"," return True"," # False if n is negative, is 1, or not whole, or if n is divisible by 2 or 3."," if n <= 1 or n % 1 != 0 or n % 2 == 0 or n % 3 == 0:"," return False"," # Check all the numbers of form 6k +/- 1, up to sqrt(n)."," for x in range(6, int(math.sqrt(n)) + 2, 6):"," if n % (x - 1) == 0 or n % (x + 1) == 0:",
|
||||
" return False"," return True"])+"("+b+")",Blockly.Python.ORDER_FUNCTION_CALL];switch(c){case "EVEN":var d=b+" % 2 == 0";break;case "ODD":d=b+" % 2 == 1";break;case "WHOLE":d=b+" % 1 == 0";break;case "POSITIVE":d=b+" > 0";break;case "NEGATIVE":d=b+" < 0";break;case "DIVISIBLE_BY":a=Blockly.Python.valueToCode(a,"DIVISOR",Blockly.Python.ORDER_MULTIPLICATIVE);if(!a||"0"==a)return["False",Blockly.Python.ORDER_ATOMIC];d=b+" % "+a+" == 0"}return[d,Blockly.Python.ORDER_RELATIONAL]};
|
||||
Blockly.Python.math_change=function(a){Blockly.Python.definitions_.from_numbers_import_Number="from numbers import Number";var b=Blockly.Python.valueToCode(a,"DELTA",Blockly.Python.ORDER_ADDITIVE)||"0";a=Blockly.Python.variableDB_.getName(a.getFieldValue("VAR"),Blockly.VARIABLE_CATEGORY_NAME);return a+" = ("+a+" if isinstance("+a+", Number) else 0) + "+b+"\n"};Blockly.Python.math_round=Blockly.Python.math_single;Blockly.Python.math_trig=Blockly.Python.math_single;
|
||||
Blockly.Python.math_on_list=function(a){var b=a.getFieldValue("OP");a=Blockly.Python.valueToCode(a,"LIST",Blockly.Python.ORDER_NONE)||"[]";switch(b){case "SUM":b="sum("+a+")";break;case "MIN":b="min("+a+")";break;case "MAX":b="max("+a+")";break;case "AVERAGE":Blockly.Python.definitions_.from_numbers_import_Number="from numbers import Number";b=Blockly.Python.provideFunction_("math_mean",["def "+Blockly.Python.FUNCTION_NAME_PLACEHOLDER_+"(myList):"," localList = [e for e in myList if isinstance(e, Number)]",
|
||||
" if not localList: return"," return float(sum(localList)) / len(localList)"]);b=b+"("+a+")";break;case "MEDIAN":Blockly.Python.definitions_.from_numbers_import_Number="from numbers import Number";b=Blockly.Python.provideFunction_("math_median",["def "+Blockly.Python.FUNCTION_NAME_PLACEHOLDER_+"(myList):"," localList = sorted([e for e in myList if isinstance(e, Number)])"," if not localList: return"," if len(localList) % 2 == 0:"," return (localList[len(localList) // 2 - 1] + localList[len(localList) // 2]) / 2.0",
|
||||
" else:"," return localList[(len(localList) - 1) // 2]"]);b=b+"("+a+")";break;case "MODE":b=Blockly.Python.provideFunction_("math_modes",["def "+Blockly.Python.FUNCTION_NAME_PLACEHOLDER_+"(some_list):"," modes = []"," # Using a lists of [item, count] to keep count rather than dict",' # to avoid "unhashable" errors when the counted item is itself a list or dict.'," counts = []"," maxCount = 1"," for item in some_list:"," found = False"," for count in counts:"," if count[0] == item:",
|
||||
" count[1] += 1"," maxCount = max(maxCount, count[1])"," found = True"," if not found:"," counts.append([item, 1])"," for counted_item, item_count in counts:"," if item_count == maxCount:"," modes.append(counted_item)"," return modes"]);b=b+"("+a+")";break;case "STD_DEV":Blockly.Python.definitions_.import_math="import math";b=Blockly.Python.provideFunction_("math_standard_deviation",["def "+Blockly.Python.FUNCTION_NAME_PLACEHOLDER_+"(numbers):"," n = len(numbers)",
|
||||
" if n == 0: return"," mean = float(sum(numbers)) / n"," variance = sum((x - mean) ** 2 for x in numbers) / n"," return math.sqrt(variance)"]);b=b+"("+a+")";break;case "RANDOM":Blockly.Python.definitions_.import_random="import random";b="random.choice("+a+")";break;default:throw Error("Unknown operator: "+b);}return[b,Blockly.Python.ORDER_FUNCTION_CALL]};
|
||||
Blockly.Python.math_modulo=function(a){var b=Blockly.Python.valueToCode(a,"DIVIDEND",Blockly.Python.ORDER_MULTIPLICATIVE)||"0";a=Blockly.Python.valueToCode(a,"DIVISOR",Blockly.Python.ORDER_MULTIPLICATIVE)||"0";return[b+" % "+a,Blockly.Python.ORDER_MULTIPLICATIVE]};
|
||||
Blockly.Python.math_constrain=function(a){var b=Blockly.Python.valueToCode(a,"VALUE",Blockly.Python.ORDER_NONE)||"0",c=Blockly.Python.valueToCode(a,"LOW",Blockly.Python.ORDER_NONE)||"0";a=Blockly.Python.valueToCode(a,"HIGH",Blockly.Python.ORDER_NONE)||"float('inf')";return["min(max("+b+", "+c+"), "+a+")",Blockly.Python.ORDER_FUNCTION_CALL]};
|
||||
Blockly.Python.math_random_int=function(a){Blockly.Python.definitions_.import_random="import random";var b=Blockly.Python.valueToCode(a,"FROM",Blockly.Python.ORDER_NONE)||"0";a=Blockly.Python.valueToCode(a,"TO",Blockly.Python.ORDER_NONE)||"0";return["random.randint("+b+", "+a+")",Blockly.Python.ORDER_FUNCTION_CALL]};Blockly.Python.math_random_float=function(a){Blockly.Python.definitions_.import_random="import random";return["random.random()",Blockly.Python.ORDER_FUNCTION_CALL]};
|
||||
Blockly.Python.math_atan2=function(a){Blockly.Python.definitions_.import_math="import math";var b=Blockly.Python.valueToCode(a,"X",Blockly.Python.ORDER_NONE)||"0";return["math.atan2("+(Blockly.Python.valueToCode(a,"Y",Blockly.Python.ORDER_NONE)||"0")+", "+b+") / math.pi * 180",Blockly.Python.ORDER_MULTIPLICATIVE]};Blockly.Python.procedures={};
|
||||
Blockly.Python.procedures_defreturn=function(a){for(var b=[],c,d=a.workspace,e=Blockly.Variables.allUsedVarModels(d)||[],f=0;c=e[f];f++)c=c.name,-1==a.getVars().indexOf(c)&&b.push(Blockly.Python.variableDB_.getName(c,Blockly.VARIABLE_CATEGORY_NAME));e=Blockly.Variables.allDeveloperVariables(d);for(f=0;f<e.length;f++)b.push(Blockly.Python.variableDB_.getName(e[f],Blockly.Names.DEVELOPER_VARIABLE_TYPE));b=b.length?Blockly.Python.INDENT+"global "+b.join(", ")+"\n":"";d=Blockly.Python.variableDB_.getName(a.getFieldValue("NAME"),Blockly.PROCEDURE_CATEGORY_NAME);
|
||||
c="";Blockly.Python.STATEMENT_PREFIX&&(c+=Blockly.Python.injectId(Blockly.Python.STATEMENT_PREFIX,a));Blockly.Python.STATEMENT_SUFFIX&&(c+=Blockly.Python.injectId(Blockly.Python.STATEMENT_SUFFIX,a));c&&(c=Blockly.Python.prefixLines(c,Blockly.Python.INDENT));var l="";Blockly.Python.INFINITE_LOOP_TRAP&&(l=Blockly.Python.prefixLines(Blockly.Python.injectId(Blockly.Python.INFINITE_LOOP_TRAP,a),Blockly.Python.INDENT));var h=Blockly.Python.statementToCode(a,"STACK"),g=Blockly.Python.valueToCode(a,"RETURN",
|
||||
Blockly.Python.ORDER_NONE)||"",k="";h&&g&&(k=c);g?g=Blockly.Python.INDENT+"return "+g+"\n":h||(h=Blockly.Python.PASS);var m=[];e=a.getVars();for(f=0;f<e.length;f++)m[f]=Blockly.Python.variableDB_.getName(e[f],Blockly.VARIABLE_CATEGORY_NAME);b="def "+d+"("+m.join(", ")+"):\n"+b+c+l+h+k+g;b=Blockly.Python.scrub_(a,b);Blockly.Python.definitions_["%"+d]=b;return null};Blockly.Python.procedures_defnoreturn=Blockly.Python.procedures_defreturn;
|
||||
Blockly.Python.procedures_callreturn=function(a){for(var b=Blockly.Python.variableDB_.getName(a.getFieldValue("NAME"),Blockly.PROCEDURE_CATEGORY_NAME),c=[],d=a.getVars(),e=0;e<d.length;e++)c[e]=Blockly.Python.valueToCode(a,"ARG"+e,Blockly.Python.ORDER_NONE)||"None";return[b+"("+c.join(", ")+")",Blockly.Python.ORDER_FUNCTION_CALL]};Blockly.Python.procedures_callnoreturn=function(a){return Blockly.Python.procedures_callreturn(a)[0]+"\n"};
|
||||
Blockly.Python.procedures_ifreturn=function(a){var b="if "+(Blockly.Python.valueToCode(a,"CONDITION",Blockly.Python.ORDER_NONE)||"False")+":\n";Blockly.Python.STATEMENT_SUFFIX&&(b+=Blockly.Python.prefixLines(Blockly.Python.injectId(Blockly.Python.STATEMENT_SUFFIX,a),Blockly.Python.INDENT));a.hasReturnValue_?(a=Blockly.Python.valueToCode(a,"VALUE",Blockly.Python.ORDER_NONE)||"None",b+=Blockly.Python.INDENT+"return "+a+"\n"):b+=Blockly.Python.INDENT+"return\n";return b};Blockly.Python.texts={};Blockly.Python.text=function(a){return[Blockly.Python.quote_(a.getFieldValue("TEXT")),Blockly.Python.ORDER_ATOMIC]};Blockly.Python.text_multiline=function(a){return[Blockly.Python.multiline_quote_(a.getFieldValue("TEXT")),Blockly.Python.ORDER_ATOMIC]};Blockly.Python.text.forceString_=function(a){return Blockly.Python.text.forceString_.strRegExp.test(a)?a:"str("+a+")"};Blockly.Python.text.forceString_.strRegExp=/^\s*'([^']|\\')*'\s*$/;
|
||||
Blockly.Python.text_join=function(a){switch(a.itemCount_){case 0:return["''",Blockly.Python.ORDER_ATOMIC];case 1:return a=Blockly.Python.valueToCode(a,"ADD0",Blockly.Python.ORDER_NONE)||"''",a=Blockly.Python.text.forceString_(a),[a,Blockly.Python.ORDER_FUNCTION_CALL];case 2:var b=Blockly.Python.valueToCode(a,"ADD0",Blockly.Python.ORDER_NONE)||"''";a=Blockly.Python.valueToCode(a,"ADD1",Blockly.Python.ORDER_NONE)||"''";a=Blockly.Python.text.forceString_(b)+" + "+Blockly.Python.text.forceString_(a);
|
||||
return[a,Blockly.Python.ORDER_ADDITIVE];default:b=[];for(var c=0;c<a.itemCount_;c++)b[c]=Blockly.Python.valueToCode(a,"ADD"+c,Blockly.Python.ORDER_NONE)||"''";a=Blockly.Python.variableDB_.getDistinctName("x",Blockly.VARIABLE_CATEGORY_NAME);a="''.join([str("+a+") for "+a+" in ["+b.join(", ")+"]])";return[a,Blockly.Python.ORDER_FUNCTION_CALL]}};
|
||||
Blockly.Python.text_append=function(a){var b=Blockly.Python.variableDB_.getName(a.getFieldValue("VAR"),Blockly.VARIABLE_CATEGORY_NAME);a=Blockly.Python.valueToCode(a,"TEXT",Blockly.Python.ORDER_NONE)||"''";return b+" = str("+b+") + "+Blockly.Python.text.forceString_(a)+"\n"};Blockly.Python.text_length=function(a){return["len("+(Blockly.Python.valueToCode(a,"VALUE",Blockly.Python.ORDER_NONE)||"''")+")",Blockly.Python.ORDER_FUNCTION_CALL]};
|
||||
Blockly.Python.text_isEmpty=function(a){return["not len("+(Blockly.Python.valueToCode(a,"VALUE",Blockly.Python.ORDER_NONE)||"''")+")",Blockly.Python.ORDER_LOGICAL_NOT]};
|
||||
Blockly.Python.text_indexOf=function(a){var b="FIRST"==a.getFieldValue("END")?"find":"rfind",c=Blockly.Python.valueToCode(a,"FIND",Blockly.Python.ORDER_NONE)||"''";b=(Blockly.Python.valueToCode(a,"VALUE",Blockly.Python.ORDER_MEMBER)||"''")+"."+b+"("+c+")";return a.workspace.options.oneBasedIndex?[b+" + 1",Blockly.Python.ORDER_ADDITIVE]:[b,Blockly.Python.ORDER_FUNCTION_CALL]};
|
||||
Blockly.Python.text_charAt=function(a){var b=a.getFieldValue("WHERE")||"FROM_START",c=Blockly.Python.valueToCode(a,"VALUE",Blockly.Python.ORDER_MEMBER)||"''";switch(b){case "FIRST":return[c+"[0]",Blockly.Python.ORDER_MEMBER];case "LAST":return[c+"[-1]",Blockly.Python.ORDER_MEMBER];case "FROM_START":return a=Blockly.Python.getAdjustedInt(a,"AT"),[c+"["+a+"]",Blockly.Python.ORDER_MEMBER];case "FROM_END":return a=Blockly.Python.getAdjustedInt(a,"AT",1,!0),[c+"["+a+"]",Blockly.Python.ORDER_MEMBER];case "RANDOM":return Blockly.Python.definitions_.import_random=
|
||||
"import random",[Blockly.Python.provideFunction_("text_random_letter",["def "+Blockly.Python.FUNCTION_NAME_PLACEHOLDER_+"(text):"," x = int(random.random() * len(text))"," return text[x];"])+"("+c+")",Blockly.Python.ORDER_FUNCTION_CALL]}throw Error("Unhandled option (text_charAt).");};
|
||||
Blockly.Python.text_getSubstring=function(a){var b=a.getFieldValue("WHERE1"),c=a.getFieldValue("WHERE2"),d=Blockly.Python.valueToCode(a,"STRING",Blockly.Python.ORDER_MEMBER)||"''";switch(b){case "FROM_START":b=Blockly.Python.getAdjustedInt(a,"AT1");"0"==b&&(b="");break;case "FROM_END":b=Blockly.Python.getAdjustedInt(a,"AT1",1,!0);break;case "FIRST":b="";break;default:throw Error("Unhandled option (text_getSubstring)");}switch(c){case "FROM_START":a=Blockly.Python.getAdjustedInt(a,"AT2",1);break;case "FROM_END":a=
|
||||
Blockly.Python.getAdjustedInt(a,"AT2",0,!0);Blockly.isNumber(String(a))?"0"==a&&(a=""):(Blockly.Python.definitions_.import_sys="import sys",a+=" or sys.maxsize");break;case "LAST":a="";break;default:throw Error("Unhandled option (text_getSubstring)");}return[d+"["+b+" : "+a+"]",Blockly.Python.ORDER_MEMBER]};
|
||||
Blockly.Python.text_changeCase=function(a){var b={UPPERCASE:".upper()",LOWERCASE:".lower()",TITLECASE:".title()"}[a.getFieldValue("CASE")];return[(Blockly.Python.valueToCode(a,"TEXT",Blockly.Python.ORDER_MEMBER)||"''")+b,Blockly.Python.ORDER_FUNCTION_CALL]};Blockly.Python.text_trim=function(a){var b={LEFT:".lstrip()",RIGHT:".rstrip()",BOTH:".strip()"}[a.getFieldValue("MODE")];return[(Blockly.Python.valueToCode(a,"TEXT",Blockly.Python.ORDER_MEMBER)||"''")+b,Blockly.Python.ORDER_FUNCTION_CALL]};
|
||||
Blockly.Python.text_print=function(a){return"print("+(Blockly.Python.valueToCode(a,"TEXT",Blockly.Python.ORDER_NONE)||"''")+")\n"};
|
||||
Blockly.Python.text_prompt_ext=function(a){var b=Blockly.Python.provideFunction_("text_prompt",["def "+Blockly.Python.FUNCTION_NAME_PLACEHOLDER_+"(msg):"," try:"," return raw_input(msg)"," except NameError:"," return input(msg)"]),c=a.getField("TEXT")?Blockly.Python.quote_(a.getFieldValue("TEXT")):Blockly.Python.valueToCode(a,"TEXT",Blockly.Python.ORDER_NONE)||"''";b=b+"("+c+")";"NUMBER"==a.getFieldValue("TYPE")&&(b="float("+b+")");return[b,Blockly.Python.ORDER_FUNCTION_CALL]};
|
||||
Blockly.Python.text_prompt=Blockly.Python.text_prompt_ext;Blockly.Python.text_count=function(a){var b=Blockly.Python.valueToCode(a,"TEXT",Blockly.Python.ORDER_MEMBER)||"''";a=Blockly.Python.valueToCode(a,"SUB",Blockly.Python.ORDER_NONE)||"''";return[b+".count("+a+")",Blockly.Python.ORDER_MEMBER]};
|
||||
Blockly.Python.text_replace=function(a){var b=Blockly.Python.valueToCode(a,"TEXT",Blockly.Python.ORDER_MEMBER)||"''",c=Blockly.Python.valueToCode(a,"FROM",Blockly.Python.ORDER_NONE)||"''";a=Blockly.Python.valueToCode(a,"TO",Blockly.Python.ORDER_NONE)||"''";return[b+".replace("+c+", "+a+")",Blockly.Python.ORDER_MEMBER]};Blockly.Python.text_reverse=function(a){return[(Blockly.Python.valueToCode(a,"TEXT",Blockly.Python.ORDER_MEMBER)||"''")+"[::-1]",Blockly.Python.ORDER_MEMBER]};Blockly.Python.variables={};Blockly.Python.variables_get=function(a){return[Blockly.Python.variableDB_.getName(a.getFieldValue("VAR"),Blockly.VARIABLE_CATEGORY_NAME),Blockly.Python.ORDER_ATOMIC]};Blockly.Python.variables_set=function(a){var b=Blockly.Python.valueToCode(a,"VALUE",Blockly.Python.ORDER_NONE)||"0";return Blockly.Python.variableDB_.getName(a.getFieldValue("VAR"),Blockly.VARIABLE_CATEGORY_NAME)+" = "+b+"\n"};Blockly.Python.variablesDynamic={};Blockly.Python.variables_get_dynamic=Blockly.Python.variables_get;Blockly.Python.variables_set_dynamic=Blockly.Python.variables_set;
|
||||
return Blockly.Python;
|
||||
}));
|
||||
|
||||
|
||||
//# sourceMappingURL=python_compressed.js.map
|
||||
1
clover_blocks/www/blockly/python_compressed.js.map
Executable file
602
clover_blocks/www/blocks.js
Normal file
@@ -0,0 +1,602 @@
|
||||
/*
|
||||
* Copyright (C) 2020 Copter Express Technologies
|
||||
*
|
||||
* Author: Oleg Kalachev <okalachev@gmail.com>
|
||||
*
|
||||
* Distributed under MIT License (available at https://opensource.org/licenses/MIT).
|
||||
* The above copyright notice and this permission notice shall be included in all
|
||||
* copies or substantial portions of the Software.
|
||||
*/
|
||||
|
||||
const COLOR_FLIGHT = 293;
|
||||
const COLOR_STATE = 36;
|
||||
const COLOR_LED = 143;
|
||||
const COLOR_GPIO = 200;
|
||||
const DOCS_URL = 'https://clover.coex.tech/en/blocks.html';
|
||||
|
||||
var frameIds = [["body", "BODY"], ["markers map", "ARUCO_MAP"], ["marker", "ARUCO"], ["last navigate target", "NAVIGATE_TARGET"], ["map", "MAP"]];
|
||||
|
||||
function considerFrameId(e) {
|
||||
if (!(e instanceof Blockly.Events.Change || e instanceof Blockly.Events.Create)) return;
|
||||
|
||||
var frameId = this.getFieldValue('FRAME_ID');
|
||||
// set appropriate coordinates labels
|
||||
if (this.getInput('X')) { // block has x-y-z fields
|
||||
if (frameId == 'BODY' || frameId == 'NAVIGATE_TARGET' || frameId == 'BASE_LINK') {
|
||||
this.getInput('X').fieldRow[0].setValue('forward');
|
||||
this.getInput('Y').fieldRow[0].setValue('left');
|
||||
this.getInput('Z').fieldRow[0].setValue('up');
|
||||
} else {
|
||||
this.getInput('X').fieldRow[0].setValue('x');
|
||||
this.getInput('Y').fieldRow[0].setValue('y');
|
||||
this.getInput('Z').fieldRow[0].setValue('z');
|
||||
}
|
||||
}
|
||||
if (this.getInput('ID')) { // block has marker id field
|
||||
this.getInput('ID').setVisible(frameId == 'ARUCO'); // toggle id field
|
||||
}
|
||||
this.render();
|
||||
}
|
||||
|
||||
function updateSetpointBlock(e) {
|
||||
if (!(e instanceof Blockly.Events.Change || e instanceof Blockly.Events.Create)) return;
|
||||
|
||||
considerFrameId.apply(this, arguments);
|
||||
|
||||
var type = this.getFieldValue('TYPE');
|
||||
var velocity = type == 'VELOCITY';
|
||||
var attitude = type == 'ATTITUDE' || type == 'RATES';
|
||||
|
||||
this.getInput('VX').setVisible(velocity);
|
||||
this.getInput('VY').setVisible(velocity);
|
||||
this.getInput('VZ').setVisible(velocity);
|
||||
this.getInput('YAW').setVisible(attitude);
|
||||
this.getInput('PITCH').setVisible(attitude);
|
||||
this.getInput('ROLL').setVisible(attitude);
|
||||
this.getInput('THRUST').setVisible(attitude);
|
||||
this.getInput('RELATIVE_TO').setVisible(type != 'RATES');
|
||||
|
||||
if (type == 'RATES') {
|
||||
this.getInput('ID').setVisible(false);
|
||||
}
|
||||
|
||||
this.render();
|
||||
}
|
||||
|
||||
Blockly.Blocks['navigate'] = {
|
||||
init: function () {
|
||||
this.appendDummyInput()
|
||||
.appendField("navigate to point");
|
||||
this.appendValueInput("X")
|
||||
.setCheck("Number")
|
||||
.appendField("forward");
|
||||
this.appendValueInput("Y")
|
||||
.setCheck("Number")
|
||||
.appendField("left");
|
||||
this.appendValueInput("Z")
|
||||
.setCheck("Number")
|
||||
.appendField("up");
|
||||
this.appendDummyInput()
|
||||
.appendField("relative to")
|
||||
.appendField(new Blockly.FieldDropdown(frameIds), "FRAME_ID");
|
||||
this.appendValueInput("ID")
|
||||
.setCheck("Number")
|
||||
.appendField("with ID")
|
||||
.setVisible(false)
|
||||
this.appendValueInput("SPEED")
|
||||
.setCheck("Number")
|
||||
.appendField("with speed");
|
||||
this.appendDummyInput()
|
||||
.appendField("wait")
|
||||
.appendField(new Blockly.FieldCheckbox("TRUE"), "WAIT");
|
||||
this.setInputsInline(false);
|
||||
this.setPreviousStatement(true, null);
|
||||
this.setNextStatement(true, null);
|
||||
this.setColour(COLOR_FLIGHT);
|
||||
this.setTooltip("Navigate to the specified point, coordinates are in meters.");
|
||||
this.setHelpUrl(DOCS_URL + '#' + this.type);
|
||||
this.setOnChange(considerFrameId);
|
||||
}
|
||||
};
|
||||
|
||||
Blockly.Blocks['set_velocity'] = {
|
||||
init: function () {
|
||||
this.appendDummyInput()
|
||||
.appendField("set velocity");
|
||||
this.appendValueInput("X")
|
||||
.setCheck("Number")
|
||||
.appendField("forward");
|
||||
this.appendValueInput("Y")
|
||||
.setCheck("Number")
|
||||
.appendField("left");
|
||||
this.appendValueInput("Z")
|
||||
.setCheck("Number")
|
||||
.appendField("up");
|
||||
this.appendDummyInput()
|
||||
.appendField("relative to")
|
||||
.appendField(new Blockly.FieldDropdown(frameIds), "FRAME_ID");
|
||||
this.appendValueInput("ID")
|
||||
.setCheck("Number")
|
||||
.appendField("with ID")
|
||||
.setVisible(false)
|
||||
this.setInputsInline(false);
|
||||
this.setPreviousStatement(true, null);
|
||||
this.setNextStatement(true, null);
|
||||
this.setColour(COLOR_FLIGHT);
|
||||
this.setTooltip("Set the drone velocity in meters per second (cancels navigation requests).");
|
||||
this.setHelpUrl(DOCS_URL + '#' + this.type);
|
||||
this.setOnChange(considerFrameId);
|
||||
}
|
||||
};
|
||||
|
||||
Blockly.Blocks['setpoint'] = {
|
||||
init: function () {
|
||||
this.appendDummyInput()
|
||||
.appendField("set");
|
||||
this.appendDummyInput()
|
||||
.appendField(new Blockly.FieldDropdown([["velocity", "VELOCITY"], ["attitude", "ATTITUDE"], ["angular rates", "RATES"]]), "TYPE");
|
||||
this.appendValueInput("VX")
|
||||
.setCheck("Number")
|
||||
.appendField("vx");
|
||||
this.appendValueInput("VY")
|
||||
.setCheck("Number")
|
||||
.appendField("vy");
|
||||
this.appendValueInput("VZ")
|
||||
.setCheck("Number")
|
||||
.appendField("vz");
|
||||
this.appendValueInput("PITCH")
|
||||
.setCheck("Number")
|
||||
.appendField("pitch")
|
||||
.setVisible(false);
|
||||
this.appendValueInput("ROLL")
|
||||
.setCheck("Number")
|
||||
.appendField("roll")
|
||||
.setVisible(false);
|
||||
this.appendValueInput("YAW")
|
||||
.setCheck("Number")
|
||||
.appendField("yaw")
|
||||
.setVisible(false);
|
||||
this.appendValueInput("THRUST")
|
||||
.setCheck("Number")
|
||||
.appendField("thrust")
|
||||
.setVisible(false);
|
||||
this.appendDummyInput('RELATIVE_TO')
|
||||
.appendField("relative to")
|
||||
.appendField(new Blockly.FieldDropdown(frameIds), "FRAME_ID");
|
||||
this.appendValueInput("ID")
|
||||
.setCheck("Number")
|
||||
.appendField("with ID")
|
||||
.setVisible(false);
|
||||
this.setInputsInline(false);
|
||||
this.setPreviousStatement(true, null);
|
||||
this.setNextStatement(true, null);
|
||||
this.setColour(COLOR_FLIGHT);
|
||||
this.setTooltip("Set the drone's setpoints of different types (cancels navigation requests).");
|
||||
this.setHelpUrl(DOCS_URL + '#' + this.type);
|
||||
this.setOnChange(updateSetpointBlock);
|
||||
}
|
||||
};
|
||||
|
||||
Blockly.Blocks['rangefinder_distance'] = {
|
||||
init: function () {
|
||||
this.appendDummyInput()
|
||||
.appendField("current rangefinder distance");
|
||||
this.setOutput(true, "Number");
|
||||
this.setColour(COLOR_STATE);
|
||||
this.setTooltip("");
|
||||
this.setHelpUrl(DOCS_URL + '#' + this.type);
|
||||
}
|
||||
};
|
||||
|
||||
Blockly.Blocks['get_position'] = {
|
||||
init: function () {
|
||||
this.appendDummyInput()
|
||||
.appendField("current")
|
||||
.appendField(new Blockly.FieldDropdown([["x", "X"], ["y", "Y"], ["z", "Z"], ["vx", "VX"], ["vy", "VY"], ["vz", "VZ"]]), "FIELD")
|
||||
.appendField("relative to")
|
||||
.appendField(new Blockly.FieldDropdown(frameIds), "FRAME_ID");
|
||||
this.appendValueInput("ID")
|
||||
.setCheck("Number")
|
||||
.appendField("with ID")
|
||||
.setVisible(false)
|
||||
this.setOutput(true, "Number");
|
||||
this.setColour(COLOR_STATE);
|
||||
this.setTooltip("Returns current position or velocity in meters or meters per second.");
|
||||
this.setHelpUrl(DOCS_URL + '#' + this.type);
|
||||
this.setOnChange(considerFrameId);
|
||||
}
|
||||
};
|
||||
|
||||
Blockly.Blocks['get_yaw'] = {
|
||||
init: function () {
|
||||
this.appendDummyInput()
|
||||
.appendField("current yaw relative to")
|
||||
.appendField(new Blockly.FieldDropdown(frameIds), "FRAME_ID");
|
||||
this.appendValueInput("ID")
|
||||
.setCheck("Number")
|
||||
.appendField("with ID")
|
||||
.setVisible(false)
|
||||
this.setOutput(true, "Number");
|
||||
this.setColour(COLOR_STATE);
|
||||
this.setTooltip("Returns current yaw in degree (not radian).");
|
||||
this.setHelpUrl(DOCS_URL + '#' + this.type);
|
||||
this.setOnChange(considerFrameId);
|
||||
}
|
||||
};
|
||||
|
||||
Blockly.Blocks['get_attitude'] = {
|
||||
init: function () {
|
||||
this.appendDummyInput()
|
||||
.appendField("current")
|
||||
.appendField(new Blockly.FieldDropdown([["pitch", "PITCH"], ["roll", "ROLL"], ["pitch rate", "PITCH_RATE"], ["roll rate", "ROLL_RATE"], ["yaw rate", "YAW_RATE"]]), "FIELD");
|
||||
this.setOutput(true, "Number");
|
||||
this.setColour(COLOR_STATE);
|
||||
this.setTooltip("Returns current orientation or angle rates in degree or degree per second (not radian).");
|
||||
this.setHelpUrl(DOCS_URL + '#' + this.type);
|
||||
}
|
||||
};
|
||||
|
||||
Blockly.Blocks['voltage'] = {
|
||||
init: function () {
|
||||
this.appendDummyInput()
|
||||
.appendField("current")
|
||||
.appendField(new Blockly.FieldDropdown([["total", "VOLTAGE"], ["cell", "CELL_VOLTAGE"]]), "TYPE")
|
||||
.appendField("voltage");
|
||||
this.setOutput(true, "Number");
|
||||
this.setColour(COLOR_STATE);
|
||||
this.setTooltip("Returns current battery voltage in volts.");
|
||||
this.setHelpUrl(DOCS_URL + '#' + this.type);
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
Blockly.Blocks['armed'] = {
|
||||
init: function () {
|
||||
this.appendDummyInput()
|
||||
.appendField("armed?");
|
||||
this.setOutput(true, "Boolean");
|
||||
this.setColour(COLOR_STATE);
|
||||
this.setTooltip("Returns if the drone armed.");
|
||||
this.setHelpUrl(DOCS_URL + '#' + this.type);
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
Blockly.Blocks['mode'] = {
|
||||
init: function () {
|
||||
this.appendDummyInput()
|
||||
.appendField("current flight mode");
|
||||
this.setOutput(true, "String");
|
||||
this.setColour(COLOR_STATE);
|
||||
this.setTooltip("");
|
||||
this.setHelpUrl(DOCS_URL + '#' + this.type);
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
Blockly.Blocks['wait_arrival'] = {
|
||||
init: function () {
|
||||
this.appendDummyInput()
|
||||
.appendField("wait arrival");
|
||||
this.setPreviousStatement(true, null);
|
||||
this.setNextStatement(true, null);
|
||||
this.setColour(COLOR_FLIGHT);
|
||||
this.setTooltip("Wait until the drone arrives to the navigation target.");
|
||||
this.setHelpUrl(DOCS_URL + '#' + this.type);
|
||||
}
|
||||
};
|
||||
|
||||
Blockly.Blocks['get_time'] = {
|
||||
init: function () {
|
||||
this.appendDummyInput()
|
||||
.appendField("time");
|
||||
this.setOutput(true, "Number");
|
||||
this.setColour(COLOR_STATE);
|
||||
this.setTooltip("Returns current timestamp in seconds.");
|
||||
this.setHelpUrl(DOCS_URL + '#' + this.type);
|
||||
}
|
||||
};
|
||||
|
||||
Blockly.Blocks['arrived'] = {
|
||||
init: function () {
|
||||
this.appendDummyInput()
|
||||
.appendField("arrived?");
|
||||
this.setOutput(true, "Boolean");
|
||||
this.setColour(COLOR_STATE);
|
||||
this.setTooltip("Returns if the drone arrived to the navigation target.");
|
||||
this.setHelpUrl(DOCS_URL + '#' + this.type);
|
||||
}
|
||||
};
|
||||
|
||||
Blockly.Blocks['set_led'] = {
|
||||
init: function () {
|
||||
this.appendDummyInput()
|
||||
.appendField("set LED");
|
||||
this.appendValueInput("INDEX")
|
||||
.setCheck("Number");
|
||||
this.appendValueInput("COLOR")
|
||||
.setCheck("Colour")
|
||||
.appendField("to color");
|
||||
this.setInputsInline(true);
|
||||
this.setPreviousStatement(true, null);
|
||||
this.setNextStatement(true, null);
|
||||
this.setColour(COLOR_LED);
|
||||
this.setTooltip("Set an individual LED to specified color.");
|
||||
this.setHelpUrl(DOCS_URL + '#' + this.type);
|
||||
}
|
||||
};
|
||||
|
||||
Blockly.Blocks['set_effect'] = {
|
||||
init: function () {
|
||||
this.appendDummyInput()
|
||||
.appendField("set LED effect")
|
||||
.appendField(new Blockly.FieldDropdown([["fill", "FILL"], ["blink", "BLINK"], ["fast blink", "BLINK_FAST"], ["fade", "FADE"], ["wipe", "WIPE"], ["flash", "FLASH"], ["rainbow", "RAINBOW"], ["rainbow fill", "RAINBOW_FILL"]]), "EFFECT");
|
||||
this.appendValueInput("COLOR")
|
||||
.setCheck("Colour")
|
||||
.appendField("with color");
|
||||
this.setInputsInline(true);
|
||||
this.setPreviousStatement(true, null);
|
||||
this.setNextStatement(true, null);
|
||||
this.setColour(COLOR_LED);
|
||||
this.setTooltip("Set desired LED strip effect.");
|
||||
this.setHelpUrl(DOCS_URL + '#' + this.type);
|
||||
|
||||
this.setOnChange(function(e) {
|
||||
if (!(e instanceof Blockly.Events.Change || e instanceof Blockly.Events.Create)) return;
|
||||
|
||||
// Hide color field on some effects
|
||||
var effect = this.getFieldValue('EFFECT');
|
||||
var hideColor = effect == 'RAINBOW' || effect == 'RAINBOW_FILL';
|
||||
this.inputList[1].setVisible(!hideColor);
|
||||
this.render();
|
||||
});
|
||||
}
|
||||
};
|
||||
|
||||
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'] = {
|
||||
init: function () {
|
||||
this.appendValueInput("ALT")
|
||||
.setCheck("Number")
|
||||
.appendField("take off to");
|
||||
this.appendDummyInput()
|
||||
.appendField("wait")
|
||||
.appendField(new Blockly.FieldCheckbox("TRUE"), "WAIT");
|
||||
this.setPreviousStatement(true, null);
|
||||
this.setNextStatement(true, null);
|
||||
this.setColour(COLOR_FLIGHT);
|
||||
this.setTooltip("Take off on desired altitude in meters");
|
||||
this.setHelpUrl(DOCS_URL + '#' + this.type);
|
||||
}
|
||||
};
|
||||
|
||||
Blockly.Blocks['land'] = {
|
||||
init: function () {
|
||||
this.appendDummyInput()
|
||||
.appendField("land");
|
||||
this.appendDummyInput()
|
||||
.appendField("wait")
|
||||
.appendField(new Blockly.FieldCheckbox("TRUE"), "WAIT");
|
||||
this.setInputsInline(true);
|
||||
this.setPreviousStatement(true, null);
|
||||
this.setNextStatement(true, null);
|
||||
this.setColour(COLOR_FLIGHT);
|
||||
this.setTooltip("");
|
||||
this.setHelpUrl(DOCS_URL + '#' + this.type);
|
||||
}
|
||||
};
|
||||
|
||||
Blockly.Blocks['global_position'] = {
|
||||
init: function () {
|
||||
this.appendDummyInput()
|
||||
.appendField("current")
|
||||
.appendField(new Blockly.FieldDropdown([["latitude", "LATITUDE"], ["longitude", "LONGITUDE"], ["altitude", "ALTITUDE"]]), "NAME");
|
||||
this.setOutput(true, "Number");
|
||||
this.setColour(230);
|
||||
this.setTooltip("");
|
||||
this.setHelpUrl(DOCS_URL + '#' + this.type);
|
||||
}
|
||||
};
|
||||
|
||||
Blockly.Blocks['on_take_off'] = {
|
||||
init: function () {
|
||||
this.appendStatementInput("TAKE_OFF")
|
||||
.setCheck(null)
|
||||
.appendField("When took off");
|
||||
this.setColour(230);
|
||||
this.setTooltip("");
|
||||
this.setHelpUrl(DOCS_URL + '#' + this.type);
|
||||
}
|
||||
};
|
||||
|
||||
Blockly.Blocks['on_landing'] = {
|
||||
init: function () {
|
||||
this.appendStatementInput("LAND")
|
||||
.setCheck(null)
|
||||
.appendField("When landed");
|
||||
this.setColour(230);
|
||||
this.setTooltip("");
|
||||
this.setHelpUrl(DOCS_URL + '#' + this.type);
|
||||
}
|
||||
};
|
||||
|
||||
Blockly.Blocks['on_armed'] = {
|
||||
init: function () {
|
||||
this.appendStatementInput("ARMED")
|
||||
.setCheck(null)
|
||||
.appendField("when armed");
|
||||
this.setColour(230);
|
||||
this.setTooltip("");
|
||||
this.setHelpUrl(DOCS_URL + '#' + this.type);
|
||||
}
|
||||
};
|
||||
|
||||
Blockly.FieldAngle.WRAP = 180;
|
||||
Blockly.FieldAngle.ROUND = 10;
|
||||
|
||||
Blockly.Blocks['angle'] = {
|
||||
init: function () {
|
||||
this.appendDummyInput()
|
||||
.appendField(new Blockly.FieldAngle(90), "ANGLE");
|
||||
this.setOutput(true, "Number");
|
||||
this.setColour(230);
|
||||
this.setTooltip("");
|
||||
this.setHelpUrl(DOCS_URL + '#' + this.type);
|
||||
}
|
||||
};
|
||||
|
||||
Blockly.Blocks['set_yaw'] = {
|
||||
init: function () {
|
||||
this.appendValueInput("YAW")
|
||||
.setCheck("Number")
|
||||
.appendField("rotate by");
|
||||
this.appendDummyInput()
|
||||
.appendField("relative to")
|
||||
.appendField(new Blockly.FieldDropdown([["body", "body"], ["markers map", "aruco_map"], ["last navigate target", "navigate_target"]]), "FRAME_ID");
|
||||
this.appendDummyInput()
|
||||
.appendField("wait")
|
||||
.appendField(new Blockly.FieldCheckbox("TRUE"), "WAIT");
|
||||
this.setInputsInline(true);
|
||||
this.setPreviousStatement(true, null);
|
||||
this.setNextStatement(true, null);
|
||||
this.setColour(COLOR_FLIGHT);
|
||||
this.setTooltip("Rotate the drone to the specified angle in degree (not radian).");
|
||||
this.setHelpUrl(DOCS_URL + '#' + this.type);
|
||||
}
|
||||
};
|
||||
|
||||
Blockly.Blocks['distance'] = {
|
||||
init: function () {
|
||||
this.appendDummyInput()
|
||||
.appendField("distance to point");
|
||||
this.appendValueInput("X")
|
||||
.setCheck("Number")
|
||||
.appendField("x");
|
||||
this.appendValueInput("Y")
|
||||
.setCheck("Number")
|
||||
.appendField("y");
|
||||
this.appendValueInput("Z")
|
||||
.setCheck("Number")
|
||||
.appendField("z");
|
||||
this.appendDummyInput()
|
||||
.appendField("relative to")
|
||||
.appendField(new Blockly.FieldDropdown([["markers map", "ARUCO_MAP"], ["marker", "ARUCO"], ["last navigate target", "NAVIGATE_TARGET"]]), "FRAME_ID");
|
||||
this.appendValueInput("ID")
|
||||
.setCheck("Number")
|
||||
.appendField("with ID")
|
||||
.setVisible(false);
|
||||
this.setInputsInline(false);
|
||||
this.setOutput(true, "Number");
|
||||
this.setColour(COLOR_STATE);
|
||||
this.setTooltip("Returns the distance to the given point in meters.");
|
||||
this.setHelpUrl(DOCS_URL + '#' + this.type);
|
||||
this.setOnChange(considerFrameId);
|
||||
}
|
||||
};
|
||||
|
||||
Blockly.Blocks['wait'] = {
|
||||
init: function () {
|
||||
this.appendDummyInput()
|
||||
.appendField("wait");
|
||||
this.appendValueInput("TIME")
|
||||
.setCheck("Number");
|
||||
this.appendDummyInput()
|
||||
.appendField("seconds");
|
||||
this.setPreviousStatement(true, null);
|
||||
this.setNextStatement(true, null);
|
||||
this.setColour(COLOR_FLIGHT);
|
||||
this.setTooltip("");
|
||||
this.setHelpUrl(DOCS_URL + '#' + this.type);
|
||||
}
|
||||
};
|
||||
|
||||
var keys = [['up', 'UP'], ['down', 'DOWN'], ['left', 'LEFT'], ['right', 'RIGHT'], ['space', 'SPACE']];
|
||||
|
||||
Blockly.Blocks['key_pressed'] = {
|
||||
init: function () {
|
||||
this.appendDummyInput()
|
||||
.appendField("key")
|
||||
.appendField(new Blockly.FieldDropdown(keys, "NAME"))
|
||||
.appendField("pressed");
|
||||
this.appendStatementInput("PRESSED")
|
||||
.setCheck(null);
|
||||
this.setPreviousStatement(true, null);
|
||||
this.setNextStatement(true, null);
|
||||
this.setColour(230);
|
||||
this.setTooltip("");
|
||||
this.setHelpUrl(DOCS_URL + '#' + this.type);
|
||||
}
|
||||
};
|
||||
|
||||
Blockly.Blocks['gpio_read'] = {
|
||||
init: function () {
|
||||
this.appendValueInput("PIN")
|
||||
.setCheck("Number")
|
||||
.appendField("read GPIO pin");
|
||||
this.setOutput(true, "Boolean");
|
||||
this.setColour(COLOR_GPIO);
|
||||
this.setTooltip("Returns if there is voltage on a GPIO pin.");
|
||||
this.setHelpUrl(DOCS_URL + '#GPIO');
|
||||
}
|
||||
};
|
||||
|
||||
Blockly.Blocks['gpio_write'] = {
|
||||
init: function () {
|
||||
this.appendValueInput("PIN")
|
||||
.setCheck("Number")
|
||||
.appendField("set GPIO pin");
|
||||
this.appendValueInput("LEVEL")
|
||||
.setCheck("Boolean")
|
||||
.appendField("to");
|
||||
this.setInputsInline(true);
|
||||
this.setColour(COLOR_GPIO);
|
||||
this.setPreviousStatement(true, null);
|
||||
this.setNextStatement(true, null);
|
||||
this.setTooltip("Set GPIO pin level.");
|
||||
this.setHelpUrl(DOCS_URL + '#GPIO');
|
||||
}
|
||||
};
|
||||
|
||||
Blockly.Blocks['set_servo'] = {
|
||||
init: function () {
|
||||
this.appendValueInput("PIN")
|
||||
.setCheck("Number")
|
||||
.appendField("set GPIO pin");
|
||||
this.appendValueInput("PWM")
|
||||
.setCheck("Number")
|
||||
.appendField("to PWM");
|
||||
this.setInputsInline(true);
|
||||
this.setColour(COLOR_GPIO);
|
||||
this.setPreviousStatement(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.setHelpUrl(DOCS_URL + '#GPIO');
|
||||
}
|
||||
};
|
||||
|
||||
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');
|
||||
}
|
||||
};
|
||||
6
clover_blocks/www/highlight/highlight.pack.js
Normal file
83
clover_blocks/www/highlight/styles/monokai-sublime.css
Normal file
@@ -0,0 +1,83 @@
|
||||
/*
|
||||
|
||||
Monokai Sublime style. Derived from Monokai by noformnocontent http://nn.mit-license.org/
|
||||
|
||||
*/
|
||||
|
||||
.hljs {
|
||||
display: block;
|
||||
overflow-x: auto;
|
||||
padding: 0.5em;
|
||||
background: #23241f;
|
||||
}
|
||||
|
||||
.hljs,
|
||||
.hljs-tag,
|
||||
.hljs-subst {
|
||||
color: #f8f8f2;
|
||||
}
|
||||
|
||||
.hljs-strong,
|
||||
.hljs-emphasis {
|
||||
color: #a8a8a2;
|
||||
}
|
||||
|
||||
.hljs-bullet,
|
||||
.hljs-quote,
|
||||
.hljs-number,
|
||||
.hljs-regexp,
|
||||
.hljs-literal,
|
||||
.hljs-link {
|
||||
color: #ae81ff;
|
||||
}
|
||||
|
||||
.hljs-code,
|
||||
.hljs-title,
|
||||
.hljs-section,
|
||||
.hljs-selector-class {
|
||||
color: #a6e22e;
|
||||
}
|
||||
|
||||
.hljs-strong {
|
||||
font-weight: bold;
|
||||
}
|
||||
|
||||
.hljs-emphasis {
|
||||
font-style: italic;
|
||||
}
|
||||
|
||||
.hljs-keyword,
|
||||
.hljs-selector-tag,
|
||||
.hljs-name,
|
||||
.hljs-attr {
|
||||
color: #f92672;
|
||||
}
|
||||
|
||||
.hljs-symbol,
|
||||
.hljs-attribute {
|
||||
color: #66d9ef;
|
||||
}
|
||||
|
||||
.hljs-params,
|
||||
.hljs-class .hljs-title {
|
||||
color: #f8f8f2;
|
||||
}
|
||||
|
||||
.hljs-string,
|
||||
.hljs-type,
|
||||
.hljs-built_in,
|
||||
.hljs-builtin-name,
|
||||
.hljs-selector-id,
|
||||
.hljs-selector-attr,
|
||||
.hljs-selector-pseudo,
|
||||
.hljs-addition,
|
||||
.hljs-variable,
|
||||
.hljs-template-variable {
|
||||
color: #e6db74;
|
||||
}
|
||||
|
||||
.hljs-comment,
|
||||
.hljs-deletion,
|
||||
.hljs-meta {
|
||||
color: #75715e;
|
||||
}
|
||||
488
clover_blocks/www/index.html
Normal file
@@ -0,0 +1,488 @@
|
||||
<!DOCTYPE html>
|
||||
<html lang="en">
|
||||
<head>
|
||||
<title>Clover Blocks</title>
|
||||
<meta charset="UTF-8">
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1, shrink-to-fit=no">
|
||||
<link rel="stylesheet" href="main.css">
|
||||
<link rel="icon" href="data:,">
|
||||
<link rel="stylesheet" href="highlight/styles/monokai-sublime.css">
|
||||
<script src="highlight/highlight.pack.js"></script>
|
||||
<script src="roslib.js"></script>
|
||||
<script src="blockly/blockly_compressed.js"></script>
|
||||
<script src="blockly/python_compressed.js"></script>
|
||||
<script src="blockly/blocks_compressed.js"></script>
|
||||
<script src="blockly/msg/js/en.js"></script>
|
||||
<script type="module" src="main.js"></script>
|
||||
</head>
|
||||
|
||||
<body data-tab="blocks">
|
||||
<ul id="tabs">
|
||||
<li class="selected" data-tab="blocks">Blocks</li>
|
||||
<li data-tab="python">Python</li>
|
||||
</ul>
|
||||
|
||||
<div id="tools">
|
||||
<div class="disconnected">Disconnected</div>
|
||||
<div class="backend-fail">Failed to contact with <code>clover_blocks</code> node, see <a href="../clover/docs/en/blocks.html#configuration" target="_blank">configuration</a> documentation.</div>
|
||||
<div id="running">Running...</div>
|
||||
<select id="program-name" title="Files are saved in <package_path>/programs/.">
|
||||
<option value="" disabled selected><Unsaved></option>
|
||||
<option value="@clear">Clear...</option>
|
||||
<option style="font-style: italic;" value="@save">Save... (Ctrl+S)</option>
|
||||
<optgroup label="User" data-type="user"></optgroup>
|
||||
<optgroup label="Examples" data-type="example"></optgroup>
|
||||
</select>
|
||||
<button onclick="runProgram()" disabled id="run" disabled title="Run the program">Run</button>
|
||||
<button onclick="stopProgram()" title="Stop the program">Stop</button>
|
||||
<button onclick="land()" title="Stop the program and land">Land</button>
|
||||
</div>
|
||||
|
||||
<div id="notifications"></div>
|
||||
|
||||
<div id="blockly" class="content"></div>
|
||||
<pre id="python" class="content" contenteditable oncut="return false" onpaste="return false" onkeydown="if(!event.metaKey) return false" spellcheck="false"></pre>
|
||||
|
||||
<xml xmlns="https://developers.google.com/blockly/xml" id="toolbox" style="display: none">
|
||||
<category name="Flight" colour="#870b99">
|
||||
<block type="take_off">
|
||||
<value name="ALT"><shadow type="math_number"><field name="NUM">1</field></shadow></value>
|
||||
</block>
|
||||
<block type="navigate">
|
||||
<value name="X"><shadow type="math_number"><field name="NUM">0</field></shadow></value>
|
||||
<value name="Y"><shadow type="math_number"><field name="NUM">0</field></shadow></value>
|
||||
<value name="Z"><shadow type="math_number"><field name="NUM">0</field></shadow></value>
|
||||
<value name="SPEED"><shadow type="math_number"><field name="NUM">0.5</field></shadow></value>
|
||||
<value name="ID"><shadow type="math_number"><field name="NUM">0</field></shadow></value>
|
||||
</block>
|
||||
<block type="land"></block>
|
||||
<block type="set_yaw">
|
||||
<value name="YAW"><shadow type="angle"></shadow></value>
|
||||
</block>
|
||||
<block type="wait">
|
||||
<value name="TIME"><shadow type="math_number"><field name="NUM">3</field></shadow></value>
|
||||
</block>
|
||||
<block type="wait_arrival"></block>
|
||||
<block type="setpoint">
|
||||
<value name="VX"><shadow type="math_number"><field name="NUM">0</field></shadow></value>
|
||||
<value name="VY"><shadow type="math_number"><field name="NUM">0</field></shadow></value>
|
||||
<value name="VZ"><shadow type="math_number"><field name="NUM">0</field></shadow></value>
|
||||
<value name="PITCH"><shadow type="math_number"><field name="NUM">0</field></shadow></value>
|
||||
<value name="ROLL"><shadow type="math_number"><field name="NUM">0</field></shadow></value>
|
||||
<value name="YAW"><shadow type="math_number"><field name="NUM">0</field></shadow></value>
|
||||
<value name="THRUST"><shadow type="math_number"><field name="NUM">0.5</field></shadow></value>
|
||||
<value name="ID"><shadow type="math_number"><field name="NUM">0</field></shadow></value>
|
||||
</block>
|
||||
<!-- <block type="key_pressed"></block> -->
|
||||
</category>
|
||||
<category name="State" colour="#ff9a00">
|
||||
<block type="get_position">
|
||||
<field name="FRAME_ID">ARUCO_MAP</field>
|
||||
<value name="ID"><shadow type="math_number"><field name="NUM">0</field></shadow></value>
|
||||
</block>
|
||||
<block type="get_yaw">
|
||||
<field name="FRAME_ID">ARUCO_MAP</field>
|
||||
<value name="ID"><shadow type="math_number"><field name="NUM">0</field></shadow></value>
|
||||
</block>
|
||||
<block type="get_attitude"></block>
|
||||
<block type="distance">
|
||||
<value name="X"><shadow type="math_number"><field name="NUM">0</field></shadow></value>
|
||||
<value name="Y"><shadow type="math_number"><field name="NUM">0</field></shadow></value>
|
||||
<value name="Z"><shadow type="math_number"><field name="NUM">0</field></shadow></value>
|
||||
<value name="ID"><shadow type="math_number"><field name="NUM">0</field></shadow></value>
|
||||
</block>
|
||||
<block type="get_time"></block>
|
||||
<block type="arrived"></block>
|
||||
<block type="rangefinder_distance"></block>
|
||||
<block type="mode"></block>
|
||||
<block type="armed"></block>
|
||||
<block type="voltage"></block>
|
||||
</category>
|
||||
<category name="LED" colour="#02d754">
|
||||
<block type="set_effect">
|
||||
<value name="COLOR"><shadow type="colour_picker"></shadow></value>
|
||||
</block>
|
||||
<block type="set_led">
|
||||
<value name="INDEX"><shadow type="math_number"><field name="NUM">0</field></shadow></value>
|
||||
<value name="COLOR"><shadow type="colour_picker"></shadow></value>
|
||||
</block>
|
||||
<block type="led_count"></block>
|
||||
</category>
|
||||
<category name="GPIO" colour="#5b97cc">
|
||||
<block type="gpio_read">
|
||||
<value name="PIN"><shadow type="math_number"><field name="NUM">1</field></shadow></value>
|
||||
</block>
|
||||
<block type="gpio_write">
|
||||
<value name="PIN"><shadow type="math_number"><field name="NUM">1</field></shadow></value>
|
||||
<value name="LEVEL"><shadow type="logic_boolean"></shadow></value>
|
||||
</block>
|
||||
<block type="set_servo">
|
||||
<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>
|
||||
</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>
|
||||
<sep></sep>
|
||||
<category name="Logic" colour="#5b80a5">
|
||||
<block type="controls_if"></block>
|
||||
<block type="logic_compare">
|
||||
<field name="OP">EQ</field>
|
||||
</block>
|
||||
<block type="logic_operation">
|
||||
<field name="OP">AND</field>
|
||||
</block>
|
||||
<block type="logic_negate"></block>
|
||||
<block type="logic_boolean">
|
||||
<field name="BOOL">TRUE</field>
|
||||
</block>
|
||||
<block type="logic_null"></block>
|
||||
<block type="logic_ternary"></block>
|
||||
</category>
|
||||
<category name="Loops" colour="#5ba55b">
|
||||
<block type="controls_repeat_ext">
|
||||
<value name="TIMES">
|
||||
<shadow type="math_number">
|
||||
<field name="NUM">10</field>
|
||||
</shadow>
|
||||
</value>
|
||||
</block>
|
||||
<block type="controls_whileUntil">
|
||||
<field name="MODE">WHILE</field>
|
||||
</block>
|
||||
<block type="controls_for">
|
||||
<field name="VAR" id="SMJ.7:a)p9(!mF0x)WK~">i</field>
|
||||
<value name="FROM">
|
||||
<shadow type="math_number">
|
||||
<field name="NUM">1</field>
|
||||
</shadow>
|
||||
</value>
|
||||
<value name="TO">
|
||||
<shadow type="math_number">
|
||||
<field name="NUM">10</field>
|
||||
</shadow>
|
||||
</value>
|
||||
<value name="BY">
|
||||
<shadow type="math_number">
|
||||
<field name="NUM">1</field>
|
||||
</shadow>
|
||||
</value>
|
||||
</block>
|
||||
<block type="controls_forEach">
|
||||
<field name="VAR" id="#hg!+5qncbZDpf;c6Qiw">j</field>
|
||||
</block>
|
||||
<block type="controls_flow_statements">
|
||||
<field name="FLOW">BREAK</field>
|
||||
</block>
|
||||
</category>
|
||||
<category name="Math" colour="#5b67a5">
|
||||
<block type="math_number">
|
||||
<field name="NUM">0</field>
|
||||
</block>
|
||||
<block type="math_arithmetic">
|
||||
<field name="OP">ADD</field>
|
||||
<value name="A">
|
||||
<shadow type="math_number">
|
||||
<field name="NUM">1</field>
|
||||
</shadow>
|
||||
</value>
|
||||
<value name="B">
|
||||
<shadow type="math_number">
|
||||
<field name="NUM">1</field>
|
||||
</shadow>
|
||||
</value>
|
||||
</block>
|
||||
<block type="math_single">
|
||||
<field name="OP">ROOT</field>
|
||||
<value name="NUM">
|
||||
<shadow type="math_number">
|
||||
<field name="NUM">9</field>
|
||||
</shadow>
|
||||
</value>
|
||||
</block>
|
||||
<block type="math_trig">
|
||||
<field name="OP">SIN</field>
|
||||
<value name="NUM">
|
||||
<shadow type="math_number">
|
||||
<field name="NUM">45</field>
|
||||
</shadow>
|
||||
</value>
|
||||
</block>
|
||||
<block type="math_constant">
|
||||
<field name="CONSTANT">PI</field>
|
||||
</block>
|
||||
<block type="math_number_property">
|
||||
<mutation divisor_input="false"></mutation>
|
||||
<field name="PROPERTY">EVEN</field>
|
||||
<value name="NUMBER_TO_CHECK">
|
||||
<shadow type="math_number">
|
||||
<field name="NUM">0</field>
|
||||
</shadow>
|
||||
</value>
|
||||
</block>
|
||||
<block type="math_round">
|
||||
<field name="OP">ROUND</field>
|
||||
<value name="NUM">
|
||||
<shadow type="math_number">
|
||||
<field name="NUM">3.1</field>
|
||||
</shadow>
|
||||
</value>
|
||||
</block>
|
||||
<block type="math_on_list">
|
||||
<mutation op="SUM"></mutation>
|
||||
<field name="OP">SUM</field>
|
||||
</block>
|
||||
<block type="math_modulo">
|
||||
<value name="DIVIDEND">
|
||||
<shadow type="math_number">
|
||||
<field name="NUM">64</field>
|
||||
</shadow>
|
||||
</value>
|
||||
<value name="DIVISOR">
|
||||
<shadow type="math_number">
|
||||
<field name="NUM">10</field>
|
||||
</shadow>
|
||||
</value>
|
||||
</block>
|
||||
<block type="math_constrain">
|
||||
<value name="VALUE">
|
||||
<shadow type="math_number">
|
||||
<field name="NUM">50</field>
|
||||
</shadow>
|
||||
</value>
|
||||
<value name="LOW">
|
||||
<shadow type="math_number">
|
||||
<field name="NUM">1</field>
|
||||
</shadow>
|
||||
</value>
|
||||
<value name="HIGH">
|
||||
<shadow type="math_number">
|
||||
<field name="NUM">100</field>
|
||||
</shadow>
|
||||
</value>
|
||||
</block>
|
||||
<block type="math_random_int">
|
||||
<value name="FROM">
|
||||
<shadow type="math_number">
|
||||
<field name="NUM">1</field>
|
||||
</shadow>
|
||||
</value>
|
||||
<value name="TO">
|
||||
<shadow type="math_number">
|
||||
<field name="NUM">100</field>
|
||||
</shadow>
|
||||
</value>
|
||||
</block>
|
||||
<block type="math_random_float"></block>
|
||||
</category>
|
||||
<category name="Text" colour="#5ba58c">
|
||||
<block type="text">
|
||||
<field name="TEXT"></field>
|
||||
</block>
|
||||
<block type="text_join">
|
||||
<mutation items="2"></mutation>
|
||||
</block>
|
||||
<block type="text_append">
|
||||
<field name="VAR" id="SmwB.@#2p5}McHySTA:V">item</field>
|
||||
<value name="TEXT">
|
||||
<shadow type="text">
|
||||
<field name="TEXT"></field>
|
||||
</shadow>
|
||||
</value>
|
||||
</block>
|
||||
<block type="text_length">
|
||||
<value name="VALUE">
|
||||
<shadow type="text">
|
||||
<field name="TEXT">abc</field>
|
||||
</shadow>
|
||||
</value>
|
||||
</block>
|
||||
<block type="text_isEmpty">
|
||||
<value name="VALUE">
|
||||
<shadow type="text">
|
||||
<field name="TEXT"></field>
|
||||
</shadow>
|
||||
</value>
|
||||
</block>
|
||||
<block type="text_indexOf">
|
||||
<field name="END">FIRST</field>
|
||||
<value name="VALUE">
|
||||
<block type="variables_get">
|
||||
<field name="VAR" id="C^Ay41*aH0(G-jwM$x4w">text</field>
|
||||
</block>
|
||||
</value>
|
||||
<value name="FIND">
|
||||
<shadow type="text">
|
||||
<field name="TEXT">abc</field>
|
||||
</shadow>
|
||||
</value>
|
||||
</block>
|
||||
<block type="text_charAt">
|
||||
<mutation at="true"></mutation>
|
||||
<field name="WHERE">FROM_START</field>
|
||||
<value name="VALUE">
|
||||
<block type="variables_get">
|
||||
<field name="VAR" id="C^Ay41*aH0(G-jwM$x4w">text</field>
|
||||
</block>
|
||||
</value>
|
||||
</block>
|
||||
<block type="text_getSubstring">
|
||||
<mutation at1="true" at2="true"></mutation>
|
||||
<field name="WHERE1">FROM_START</field>
|
||||
<field name="WHERE2">FROM_START</field>
|
||||
<value name="STRING">
|
||||
<block type="variables_get">
|
||||
<field name="VAR" id="C^Ay41*aH0(G-jwM$x4w">text</field>
|
||||
</block>
|
||||
</value>
|
||||
</block>
|
||||
<block type="text_changeCase">
|
||||
<field name="CASE">UPPERCASE</field>
|
||||
<value name="TEXT">
|
||||
<shadow type="text">
|
||||
<field name="TEXT">abc</field>
|
||||
</shadow>
|
||||
</value>
|
||||
</block>
|
||||
<block type="text_trim">
|
||||
<field name="MODE">BOTH</field>
|
||||
<value name="TEXT">
|
||||
<shadow type="text">
|
||||
<field name="TEXT">abc</field>
|
||||
</shadow>
|
||||
</value>
|
||||
</block>
|
||||
<block type="text_print">
|
||||
<value name="TEXT">
|
||||
<shadow type="text">
|
||||
<field name="TEXT">abc</field>
|
||||
</shadow>
|
||||
</value>
|
||||
</block>
|
||||
<block type="text_prompt_ext">
|
||||
<mutation type="TEXT"></mutation>
|
||||
<field name="TYPE">TEXT</field>
|
||||
<value name="TEXT">
|
||||
<shadow type="text">
|
||||
<field name="TEXT">abc</field>
|
||||
</shadow>
|
||||
</value>
|
||||
</block>
|
||||
</category>
|
||||
<category name="Lists" colour="#745ba5">
|
||||
<block type="lists_create_with">
|
||||
<mutation items="0"></mutation>
|
||||
</block>
|
||||
<block type="lists_create_with">
|
||||
<mutation items="3"></mutation>
|
||||
</block>
|
||||
<block type="lists_repeat">
|
||||
<value name="NUM">
|
||||
<shadow type="math_number">
|
||||
<field name="NUM">5</field>
|
||||
</shadow>
|
||||
</value>
|
||||
</block>
|
||||
<block type="lists_length"></block>
|
||||
<block type="lists_isEmpty"></block>
|
||||
<block type="lists_indexOf">
|
||||
<field name="END">FIRST</field>
|
||||
<value name="VALUE">
|
||||
<block type="variables_get">
|
||||
<field name="VAR" id="+/w.~s(u:tRiXNBG5eR#">list</field>
|
||||
</block>
|
||||
</value>
|
||||
</block>
|
||||
<block type="lists_getIndex">
|
||||
<mutation statement="false" at="true"></mutation>
|
||||
<field name="MODE">GET</field>
|
||||
<field name="WHERE">FROM_START</field>
|
||||
<value name="VALUE">
|
||||
<block type="variables_get">
|
||||
<field name="VAR" id="+/w.~s(u:tRiXNBG5eR#">list</field>
|
||||
</block>
|
||||
</value>
|
||||
</block>
|
||||
<block type="lists_setIndex">
|
||||
<mutation at="true"></mutation>
|
||||
<field name="MODE">SET</field>
|
||||
<field name="WHERE">FROM_START</field>
|
||||
<value name="LIST">
|
||||
<block type="variables_get">
|
||||
<field name="VAR" id="+/w.~s(u:tRiXNBG5eR#">list</field>
|
||||
</block>
|
||||
</value>
|
||||
</block>
|
||||
<block type="lists_getSublist">
|
||||
<mutation at1="true" at2="true"></mutation>
|
||||
<field name="WHERE1">FROM_START</field>
|
||||
<field name="WHERE2">FROM_START</field>
|
||||
<value name="LIST">
|
||||
<block type="variables_get">
|
||||
<field name="VAR" id="+/w.~s(u:tRiXNBG5eR#">list</field>
|
||||
</block>
|
||||
</value>
|
||||
</block>
|
||||
<block type="lists_split">
|
||||
<mutation mode="SPLIT"></mutation>
|
||||
<field name="MODE">SPLIT</field>
|
||||
<value name="DELIM">
|
||||
<shadow type="text">
|
||||
<field name="TEXT">,</field>
|
||||
</shadow>
|
||||
</value>
|
||||
</block>
|
||||
<block type="lists_sort">
|
||||
<field name="TYPE">NUMERIC</field>
|
||||
<field name="DIRECTION">1</field>
|
||||
</block>
|
||||
</category>
|
||||
<category name="Colour" colour="#a5745b">
|
||||
<block type="colour_picker">
|
||||
<field name="COLOUR">#ff0000</field>
|
||||
</block>
|
||||
<block type="colour_random"></block>
|
||||
<block type="colour_rgb">
|
||||
<value name="RED">
|
||||
<shadow type="math_number">
|
||||
<field name="NUM">100</field>
|
||||
</shadow>
|
||||
</value>
|
||||
<value name="GREEN">
|
||||
<shadow type="math_number">
|
||||
<field name="NUM">50</field>
|
||||
</shadow>
|
||||
</value>
|
||||
<value name="BLUE">
|
||||
<shadow type="math_number">
|
||||
<field name="NUM">0</field>
|
||||
</shadow>
|
||||
</value>
|
||||
</block>
|
||||
<block type="colour_blend">
|
||||
<value name="COLOUR1">
|
||||
<shadow type="colour_picker">
|
||||
<field name="COLOUR">#ff0000</field>
|
||||
</shadow>
|
||||
</value>
|
||||
<value name="COLOUR2">
|
||||
<shadow type="colour_picker">
|
||||
<field name="COLOUR">#3333ff</field>
|
||||
</shadow>
|
||||
</value>
|
||||
<value name="RATIO">
|
||||
<shadow type="math_number">
|
||||
<field name="NUM">0.5</field>
|
||||
</shadow>
|
||||
</value>
|
||||
</block>
|
||||
</category>
|
||||
<sep></sep>
|
||||
<category name="Variables" colour="#a55b80" custom="VARIABLE"></category>
|
||||
<category name="Functions" colour="#995ba5" custom="PROCEDURE"></category>
|
||||
</xml>
|
||||
</body>
|
||||
|
||||
</html>
|
||||
136
clover_blocks/www/main.css
Normal file
@@ -0,0 +1,136 @@
|
||||
body, html {
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
}
|
||||
|
||||
body {
|
||||
padding: 0;
|
||||
margin: 0;
|
||||
display: grid;
|
||||
grid-template-areas:
|
||||
"tabs tools"
|
||||
"content content";
|
||||
grid-template-rows: min-content 1fr;
|
||||
grid-template-columns: 1fr min-content ;
|
||||
font-family: sans-serif;
|
||||
font-size: 16px;
|
||||
}
|
||||
|
||||
#tools, #tabs {
|
||||
background: #dddddd;
|
||||
border-bottom: 2px rgb(192, 192, 192) solid;
|
||||
white-space: nowrap;
|
||||
}
|
||||
|
||||
#tools {
|
||||
grid-area: tools;
|
||||
white-space: nowrap;
|
||||
padding: 10px;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
}
|
||||
|
||||
#program-name {
|
||||
width: 150px;
|
||||
border: none;
|
||||
font-size: 14px;
|
||||
padding: 5px;
|
||||
outline: none;
|
||||
background: transparent;
|
||||
text-overflow: ellipsis;
|
||||
}
|
||||
|
||||
#program-name:focus {
|
||||
background: white;
|
||||
}
|
||||
|
||||
.changed #program-name {
|
||||
color: red;
|
||||
}
|
||||
|
||||
.disconnected {
|
||||
color: red;
|
||||
margin-right: 20px;
|
||||
}
|
||||
|
||||
.connected .disconnected { display: none; }
|
||||
|
||||
.backend-fail {
|
||||
margin-right: 20px;
|
||||
display: none;
|
||||
}
|
||||
|
||||
@keyframes blink {
|
||||
0% { opacity: 1; }
|
||||
50% { opacity: 0.5; }
|
||||
100% { opacity: 1; }
|
||||
}
|
||||
|
||||
#running {
|
||||
color: green;
|
||||
margin-right: 20px;
|
||||
animation: 1s blink linear infinite;
|
||||
display: none;
|
||||
}
|
||||
|
||||
.running #running { display: block; }
|
||||
|
||||
#tools button {
|
||||
font-size: 20px;
|
||||
margin-left: 10px;
|
||||
}
|
||||
|
||||
#tabs {
|
||||
grid-area: tabs;
|
||||
list-style: none;
|
||||
margin: 0;
|
||||
padding: 10px;
|
||||
}
|
||||
|
||||
#tabs li {
|
||||
font-size: 18px;
|
||||
display: inline-block;
|
||||
padding: 5px 10px;
|
||||
cursor: pointer;
|
||||
}
|
||||
|
||||
#tabs li.selected {
|
||||
background: white;
|
||||
}
|
||||
|
||||
#run {
|
||||
width: 70px;
|
||||
}
|
||||
|
||||
#notifications {
|
||||
position: absolute;
|
||||
right: 10px;
|
||||
background: rgba(0, 0, 0, 0.7);
|
||||
color: white;
|
||||
max-width: 350px;
|
||||
top: 53px;
|
||||
/* border: white solid 3px; */
|
||||
z-index: 1;
|
||||
padding: 10px;
|
||||
font-family: monospace;
|
||||
font-size: 16px;
|
||||
white-space: pre;
|
||||
max-height: 400px;
|
||||
overflow: scroll;
|
||||
}
|
||||
|
||||
#notifications:empty { display: none; }
|
||||
|
||||
.content {
|
||||
display: none !important;
|
||||
grid-area: content;
|
||||
}
|
||||
|
||||
body[data-tab="blocks"] #blockly { display: block !important; }
|
||||
body[data-tab="python"] #python { display: block !important; }
|
||||
|
||||
#python {
|
||||
margin: 0px;
|
||||
padding: 10px;
|
||||
z-index: 999999; /* overlap some Blockly's popups */
|
||||
}
|
||||
325
clover_blocks/www/main.js
Normal file
@@ -0,0 +1,325 @@
|
||||
/*
|
||||
* Copyright (C) 2020 Copter Express Technologies
|
||||
*
|
||||
* Author: Oleg Kalachev <okalachev@gmail.com>
|
||||
*
|
||||
* Distributed under MIT License (available at https://opensource.org/licenses/MIT).
|
||||
* The above copyright notice and this permission notice shall be included in all
|
||||
* copies or substantial portions of the Software.
|
||||
*/
|
||||
|
||||
import * as ros from './ros.js';
|
||||
import './blocks.js';
|
||||
import {generateCode, generateUserCode} from './python.js';
|
||||
|
||||
// Tabs
|
||||
document.getElementById('tabs').addEventListener('click', function(e) {
|
||||
var tab = e.target.getAttribute('data-tab');
|
||||
if (tab) {
|
||||
for (let elem of e.target.parentElement.querySelectorAll('[data-tab]')) {
|
||||
elem.classList.remove('selected');
|
||||
}
|
||||
e.target.classList.add('selected');
|
||||
document.body.setAttribute('data-tab', tab);
|
||||
}
|
||||
});
|
||||
|
||||
var workspace = Blockly.inject('blockly', {
|
||||
toolbox: document.getElementById('toolbox'),
|
||||
grid: {
|
||||
spacing: 25,
|
||||
length: 3,
|
||||
colour: '#ccc',
|
||||
snap: true
|
||||
},
|
||||
zoom: { controls: true, wheel: true },
|
||||
media: 'blockly/media/',
|
||||
});
|
||||
|
||||
function readParams() {
|
||||
return Promise.all([
|
||||
ros.readParam('navigate_tolerance', true, 0.2),
|
||||
ros.readParam('yaw_tolerance', true, 20),
|
||||
ros.readParam('sleep_time', true, 0.2),
|
||||
ros.readParam('confirm_run', true, true),
|
||||
]);
|
||||
}
|
||||
|
||||
var ready = readParams(); // initialization complete promise
|
||||
|
||||
var pythonArea = document.getElementById('python');
|
||||
|
||||
// update Python code
|
||||
workspace.addChangeListener(function(e) {
|
||||
ready.then(function() {
|
||||
pythonArea.innerHTML = generateUserCode(workspace);
|
||||
hljs.highlightBlock(pythonArea);
|
||||
});
|
||||
});
|
||||
|
||||
var running = false;
|
||||
var runRequest = false;
|
||||
|
||||
new ROSLIB.Topic({ ros: ros.ros, name: ros.priv + 'block', messageType: 'std_msgs/String' }).subscribe(function(msg) {
|
||||
workspace.highlightBlock(msg.data);
|
||||
runRequest = false;
|
||||
update();
|
||||
});
|
||||
|
||||
new ROSLIB.Topic({ ros: ros.ros, name: ros.priv + 'running' }).subscribe(function(msg) {
|
||||
running = msg.data;
|
||||
runRequest = false;
|
||||
if (!running) {
|
||||
workspace.highlightBlock('');
|
||||
}
|
||||
update();
|
||||
});
|
||||
|
||||
var notifElem = document.getElementById('notifications');
|
||||
|
||||
function z(n) { return (n < 10 ? '0' : '') + n; } // add leading zero
|
||||
|
||||
new ROSLIB.Topic({ ros: ros.ros, name: ros.priv + 'print', messageType: 'std_msgs/String'}).subscribe(function(msg) {
|
||||
var d = new Date(); // TODO: use rosgraph_msgs/Log?
|
||||
var timestamp = `${z(d.getHours())}:${z(d.getMinutes())}:${z(d.getSeconds())}`;
|
||||
notifElem.innerHTML += `${timestamp}: ${msg.data}\n`;
|
||||
notifElem.scrollTop = notifElem.scrollHeight;
|
||||
});
|
||||
|
||||
new ROSLIB.Topic({ ros: ros.ros, name: ros.priv + 'error', messageType: 'std_msgs/String'}).subscribe(function(msg) {
|
||||
alert('Error: ' + msg.data);
|
||||
});
|
||||
|
||||
var runButton = document.getElementById('run');
|
||||
|
||||
function update() {
|
||||
document.body.classList.toggle('running', running);
|
||||
runButton.disabled = !ros.ros.isConnected || runRequest || running;
|
||||
}
|
||||
|
||||
var shownPrompts = new Set();
|
||||
|
||||
new ROSLIB.Topic({ ros: ros.ros, name: ros.priv + 'prompt', messageType: 'clover_blocks/Prompt'}).subscribe(function(msg) {
|
||||
if (shownPrompts.has(msg.id)) return;
|
||||
shownPrompts.add(msg.id);
|
||||
|
||||
var response = prompt(msg.message);
|
||||
new ROSLIB.Topic({
|
||||
ros: ros.ros,
|
||||
name: ros.priv + 'input/' + msg.id,
|
||||
messageType: 'std_msgs/String',
|
||||
latch: true
|
||||
}).publish(new ROSLIB.Message({ data: response || '' }));
|
||||
});
|
||||
|
||||
window.stopProgram = function() {
|
||||
ros.stopService.callService(new ROSLIB.ServiceRequest(), function(res) {
|
||||
if (!res.success) alert(res.message);
|
||||
}, err => alert(err))
|
||||
}
|
||||
|
||||
ros.ros.on('connection', update);
|
||||
|
||||
ros.ros.on('close', update);
|
||||
|
||||
ready.then(() => runButton.disabled = false);
|
||||
|
||||
window.runProgram = function() {
|
||||
if (ros.params.confirm_run && !confirm('Run program?')) return;
|
||||
|
||||
runRequest = true;
|
||||
update();
|
||||
var code = generateCode(workspace);
|
||||
console.log(code);
|
||||
ros.runService.callService(new ROSLIB.ServiceRequest({ code: code } ), function(res) {
|
||||
if (!res.success) {
|
||||
runRequest = false;
|
||||
update();
|
||||
alert(res.message);
|
||||
}
|
||||
}, function(err) {
|
||||
runRequest = false;
|
||||
update();
|
||||
alert(err);
|
||||
})
|
||||
}
|
||||
|
||||
window.land = function() {
|
||||
window.stopProgram();
|
||||
ros.landService.callService(new ROSLIB.ServiceRequest(), function(result) {
|
||||
}, function(err) {
|
||||
alert('Unable to land: ' + err);
|
||||
});
|
||||
}
|
||||
|
||||
function getProgramXml() {
|
||||
var xmlDom = Blockly.Xml.workspaceToDom(workspace);
|
||||
return Blockly.Xml.domToPrettyText(xmlDom);
|
||||
}
|
||||
|
||||
function setProgramXml(xml) {
|
||||
workspace.clear();
|
||||
if (xml) {
|
||||
let xmlDom = Blockly.Xml.textToDom(xml);
|
||||
Blockly.Xml.domToWorkspace(xmlDom, workspace);
|
||||
}
|
||||
}
|
||||
|
||||
workspace.addChangeListener(function(e) {
|
||||
localStorage.setItem('xml', getProgramXml());
|
||||
});
|
||||
|
||||
var programSelect = document.querySelector('#program-name');
|
||||
var userPrograms = programSelect.querySelector('optgroup[data-type=user]');
|
||||
var examplePrograms = programSelect.querySelector('optgroup[data-type=example]');
|
||||
|
||||
var programs = {};
|
||||
var program = '';
|
||||
|
||||
function loadWorkspace() {
|
||||
var xml = localStorage.getItem('xml');
|
||||
if (xml) {
|
||||
setProgramXml(xml);
|
||||
}
|
||||
program = localStorage.getItem('program') || '';
|
||||
}
|
||||
|
||||
loadWorkspace();
|
||||
|
||||
function loadPrograms() {
|
||||
ros.loadService.callService(new ROSLIB.ServiceRequest(), function(res) {
|
||||
if (!res.success) alert(res.message);
|
||||
|
||||
for (let i = 0; i < res.names.length; i++) {
|
||||
let name = res.names[i];
|
||||
let program = res.programs[i];
|
||||
let option = document.createElement('option');
|
||||
option.innerHTML = res.names[i];
|
||||
if (name.startsWith('examples/')) {
|
||||
examplePrograms.appendChild(option);
|
||||
} else {
|
||||
userPrograms.appendChild(option);
|
||||
}
|
||||
|
||||
programs[name] = program;
|
||||
}
|
||||
|
||||
if (program) {
|
||||
programSelect.value = program;
|
||||
}
|
||||
updateChanged();
|
||||
}, function(err) {
|
||||
document.querySelector('.backend-fail').style.display = 'inline';
|
||||
alert(`Error loading programs list.\n\nHave you enabled clover_blocks in clover.launch?`);
|
||||
runButton.disabled = true;
|
||||
})
|
||||
}
|
||||
|
||||
loadPrograms();
|
||||
|
||||
function getProgramName() {
|
||||
if (programSelect.value.startsWith('@')) {
|
||||
return ''
|
||||
}
|
||||
return programSelect.value;
|
||||
}
|
||||
|
||||
function updateChanged() {
|
||||
var name = program;
|
||||
document.body.classList.toggle('changed', name in programs && (programs[name].trim() != getProgramXml().trim()));
|
||||
}
|
||||
|
||||
workspace.addChangeListener(function(e) {
|
||||
if (e instanceof Blockly.Events.Change || e instanceof Blockly.Events.Create || e instanceof Blockly.Events.Delete) {
|
||||
updateChanged();
|
||||
}
|
||||
});
|
||||
|
||||
function saveProgram() {
|
||||
var name = getProgramName();
|
||||
|
||||
if (!name) {
|
||||
name = prompt('Enter new program name:');
|
||||
if (!name) {
|
||||
programSelect.value = program;
|
||||
return;
|
||||
}
|
||||
if (!name.endsWith('.xml')) {
|
||||
name += '.xml';
|
||||
}
|
||||
let option = document.createElement('option');
|
||||
option.innerHTML = name;
|
||||
userPrograms.appendChild(option);
|
||||
}
|
||||
|
||||
let xml = getProgramXml();
|
||||
ros.storeService.callService(new ROSLIB.ServiceRequest({
|
||||
name: name,
|
||||
program: xml
|
||||
}), function(result) {
|
||||
if (!result.success) {
|
||||
alert(result.message);
|
||||
return;
|
||||
}
|
||||
console.log(result.message);
|
||||
programSelect.blur();
|
||||
program = name;
|
||||
localStorage.setItem('program', name);
|
||||
programs[name] = xml;
|
||||
programSelect.value = program;
|
||||
updateChanged();
|
||||
}, function(err) {
|
||||
// TODO: restore previous state correctly
|
||||
alert('Unable to store: ' + err);
|
||||
programSelect.blur();
|
||||
programSelect.value = program;
|
||||
});
|
||||
}
|
||||
|
||||
window.addEventListener('keydown', function(e) {
|
||||
if ((e.metaKey || e.ctrlKey) && e.key == 's') { // ctrl+s/cmd+s
|
||||
e.preventDefault();
|
||||
if (!document.body.classList.contains('changed')) { // if not changed, ignore
|
||||
return;
|
||||
}
|
||||
saveProgram();
|
||||
}
|
||||
});
|
||||
|
||||
programSelect.addEventListener('change', function(e) {
|
||||
if (programSelect.value == '@clear') {
|
||||
if (!confirm('Clear workspace?')) {
|
||||
programSelect.value = program;
|
||||
return;
|
||||
}
|
||||
localStorage.removeItem('program');
|
||||
program = '';
|
||||
setProgramXml('');
|
||||
programSelect.value = program;
|
||||
programSelect.blur();
|
||||
} else if (programSelect.value == '@save') {
|
||||
saveProgram();
|
||||
} else {
|
||||
// load program
|
||||
if (program == '' || document.body.classList.contains('changed')) {
|
||||
if (!confirm('Discard changes?')) {
|
||||
programSelect.value = program;
|
||||
return;
|
||||
}
|
||||
}
|
||||
let name = programSelect.value;
|
||||
let lastProgram = getProgramXml();
|
||||
programSelect.blur();
|
||||
try {
|
||||
setProgramXml(programs[name]);
|
||||
program = name;
|
||||
localStorage.setItem('program', name);
|
||||
} catch(e) {
|
||||
alert(e);
|
||||
setProgramXml(lastProgram);
|
||||
program = ''
|
||||
programSelect.value = program;
|
||||
}
|
||||
updateChanged();
|
||||
}
|
||||
});
|
||||
466
clover_blocks/www/python.js
Normal file
@@ -0,0 +1,466 @@
|
||||
/*
|
||||
* Copyright (C) 2020 Copter Express Technologies
|
||||
*
|
||||
* Author: Oleg Kalachev <okalachev@gmail.com>
|
||||
*
|
||||
* Distributed under MIT License (available at https://opensource.org/licenses/MIT).
|
||||
* The above copyright notice and this permission notice shall be included in all
|
||||
* copies or substantial portions of the Software.
|
||||
*/
|
||||
|
||||
import {params} from './ros.js';
|
||||
|
||||
// If any new block imports any library, add that library name here.
|
||||
Blockly.Python.addReservedWords('_b,_print');
|
||||
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('pigpio,pi,Range');
|
||||
Blockly.Python.addReservedWords('SetLEDEffect,set_effect,led_count,get_led_count');
|
||||
Blockly.Python.addReservedWords('SetLEDs,LEDState,set_leds');
|
||||
|
||||
const IMPORT_SRV = `from clover import srv
|
||||
from std_srvs.srv import Trigger`;
|
||||
|
||||
const NAVIGATE_WAIT = () => `\ndef navigate_wait(x=0, y=0, z=0, speed=0.5, frame_id='body', auto_arm=False):
|
||||
res = navigate(x=x, y=y, z=z, yaw=float('nan'), speed=speed, frame_id=frame_id, auto_arm=auto_arm)
|
||||
|
||||
if not res.success:
|
||||
raise Exception(res.message)
|
||||
|
||||
while not rospy.is_shutdown():
|
||||
telem = get_telemetry(frame_id='navigate_target')
|
||||
if math.sqrt(telem.x ** 2 + telem.y ** 2 + telem.z ** 2) < ${params.navigate_tolerance}:
|
||||
return
|
||||
rospy.sleep(${params.sleep_time})\n`;
|
||||
|
||||
const LAND_WAIT = () => `\ndef land_wait():
|
||||
land()
|
||||
while get_telemetry().armed:
|
||||
rospy.sleep(${params.sleep_time})\n`;
|
||||
|
||||
const WAIT_YAW = () => `\ndef wait_yaw():
|
||||
while not rospy.is_shutdown():
|
||||
telem = get_telemetry(frame_id='navigate_target')
|
||||
if abs(telem.yaw) < math.radians(${params.yaw_tolerance}):
|
||||
return
|
||||
rospy.sleep(${params.sleep_time})\n`;
|
||||
|
||||
const WAIT_ARRIVAL = () => `\ndef wait_arrival():
|
||||
while not rospy.is_shutdown():
|
||||
telem = get_telemetry(frame_id='navigate_target')
|
||||
if math.sqrt(telem.x ** 2 + telem.y ** 2 + telem.z ** 2) < ${params.navigate_tolerance}:
|
||||
return
|
||||
rospy.sleep(${params.sleep_time})\n`;
|
||||
|
||||
const ARRIVED = () => `\ndef arrived():
|
||||
telem = get_telemetry(frame_id='navigate_target')
|
||||
return math.sqrt(telem.x ** 2 + telem.y ** 2 + telem.z ** 2) < ${params.navigate_tolerance}\n`
|
||||
|
||||
const GET_DISTANCE = `\ndef get_distance(x, y, z, frame_id):
|
||||
telem = get_telemetry(frame_id)
|
||||
return math.sqrt((x - telem.x) ** 2 + (y - telem.y) ** 2 + (z - telem.z) ** 2)\n`;
|
||||
|
||||
var rosDefinitions = {};
|
||||
|
||||
function generateROSDefinitions() {
|
||||
// order for ROS definitions is significant, so generate all ROS definitions as one
|
||||
var code = `rospy.init_node('flight')\n\n`;
|
||||
if (rosDefinitions.offboard) {
|
||||
code += `get_telemetry = rospy.ServiceProxy('get_telemetry', srv.GetTelemetry)\n`;
|
||||
code += `navigate = rospy.ServiceProxy('navigate', srv.Navigate)\n`;
|
||||
if (rosDefinitions.setVelocity) {
|
||||
code += `set_velocity = rospy.ServiceProxy('set_velocity', srv.SetVelocity)\n`;
|
||||
}
|
||||
if (rosDefinitions.setAttitude) {
|
||||
code += `set_attitude = rospy.ServiceProxy('set_attitude', srv.SetAttitude)\n`;
|
||||
}
|
||||
if (rosDefinitions.setRates) {
|
||||
code += `set_rates = rospy.ServiceProxy('set_rates', srv.SetRates)\n`;
|
||||
}
|
||||
code += `land = rospy.ServiceProxy('land', Trigger)\n`;
|
||||
}
|
||||
if (rosDefinitions.setEffect) {
|
||||
Blockly.Python.definitions_['import_led_effect'] = 'from clover.srv import SetLEDEffect';
|
||||
code += `set_effect = rospy.ServiceProxy('led/set_effect', SetLEDEffect, persistent=True)\n`;
|
||||
}
|
||||
if (rosDefinitions.setLeds) {
|
||||
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`;
|
||||
}
|
||||
if (rosDefinitions.ledStateArray) {
|
||||
Blockly.Python.definitions_['import_led_state_array'] = 'from led_msgs.msg import LEDStateArray';
|
||||
}
|
||||
if (rosDefinitions.navigateWait) {
|
||||
Blockly.Python.definitions_['import_math'] = 'import math';
|
||||
code += NAVIGATE_WAIT();
|
||||
}
|
||||
if (rosDefinitions.landWait) {
|
||||
code += LAND_WAIT();
|
||||
}
|
||||
if (rosDefinitions.waitArrival) {
|
||||
Blockly.Python.definitions_['import_math'] = 'import math';
|
||||
code += WAIT_ARRIVAL();
|
||||
}
|
||||
if (rosDefinitions.arrived) {
|
||||
Blockly.Python.definitions_['import_math'] = 'import math';
|
||||
code += ARRIVED();
|
||||
}
|
||||
if (rosDefinitions.waitYaw) {
|
||||
Blockly.Python.definitions_['import_math'] = 'import math';
|
||||
code += WAIT_YAW();
|
||||
}
|
||||
if (rosDefinitions.distance) {
|
||||
Blockly.Python.definitions_['import_math'] = 'import math';
|
||||
code += GET_DISTANCE;
|
||||
}
|
||||
Blockly.Python.definitions_['ros'] = code;
|
||||
}
|
||||
|
||||
function initNode() {
|
||||
Blockly.Python.definitions_['import_rospy'] = 'import rospy';
|
||||
generateROSDefinitions();
|
||||
}
|
||||
|
||||
function simpleOffboard() {
|
||||
rosDefinitions.offboard = true;
|
||||
Blockly.Python.definitions_['import_srv'] = IMPORT_SRV;
|
||||
initNode();
|
||||
}
|
||||
|
||||
// Adjust indentation
|
||||
Blockly.Python.INDENT = ' ';
|
||||
|
||||
export function generateUserCode(workspace) {
|
||||
rosDefinitions = {};
|
||||
Blockly.Python.STATEMENT_PREFIX = null;
|
||||
return Blockly.Python.workspaceToCode(workspace);
|
||||
}
|
||||
|
||||
export function generateCode(workspace) {
|
||||
rosDefinitions = {};
|
||||
Blockly.Python.STATEMENT_PREFIX = '_b(%1)\n';
|
||||
var code = Blockly.Python.workspaceToCode(workspace);
|
||||
return code;
|
||||
}
|
||||
|
||||
function buildFrameId(block) {
|
||||
let frame = block.getFieldValue('FRAME_ID').toLowerCase();
|
||||
let id = Blockly.Python.valueToCode(block, 'ID', Blockly.Python.ORDER_NONE);
|
||||
if (frame == 'aruco') { // aruco marker frame
|
||||
if (id.match(/^[0-9]+$/)) { // id is positive integer
|
||||
return `'${frame}_${id}'`;
|
||||
} else { // something else...
|
||||
return `'${frame}_' + str(int(${id}))`;
|
||||
}
|
||||
} else {
|
||||
return `'${frame}'`;
|
||||
}
|
||||
}
|
||||
|
||||
Blockly.Python.navigate = function(block) {
|
||||
let x = Blockly.Python.valueToCode(block, 'X', Blockly.Python.ORDER_NONE);
|
||||
let y = Blockly.Python.valueToCode(block, 'Y', Blockly.Python.ORDER_NONE);
|
||||
let z = Blockly.Python.valueToCode(block, 'Z', Blockly.Python.ORDER_NONE);
|
||||
let frameId = buildFrameId(block);
|
||||
let speed = Blockly.Python.valueToCode(block, 'SPEED', Blockly.Python.ORDER_NONE);
|
||||
|
||||
let params = [`x=${x}`, `y=${y}`, `z=${z}`, `frame_id=${frameId}`, `speed=${speed}`];
|
||||
|
||||
simpleOffboard();
|
||||
|
||||
if (block.getFieldValue('WAIT') == 'TRUE') {
|
||||
rosDefinitions.navigateWait = true;
|
||||
simpleOffboard();
|
||||
|
||||
return `navigate_wait(${params.join(', ')})\n`;
|
||||
|
||||
} else {
|
||||
if (frameId != 'body') {
|
||||
params.push(`yaw=float('nan')`);
|
||||
}
|
||||
return `navigate(${params.join(', ')})\n`;
|
||||
}
|
||||
}
|
||||
|
||||
Blockly.Python.set_velocity = function(block) {
|
||||
let x = Blockly.Python.valueToCode(block, 'X', Blockly.Python.ORDER_NONE);
|
||||
let y = Blockly.Python.valueToCode(block, 'Y', Blockly.Python.ORDER_NONE);
|
||||
let z = Blockly.Python.valueToCode(block, 'Z', Blockly.Python.ORDER_NONE);
|
||||
let frameId = buildFrameId(block);
|
||||
|
||||
simpleOffboard();
|
||||
|
||||
if (frameId == `'body'`) {
|
||||
return `set_velocity(vx=${x}, vy=${y}, vz=${z}, frame_id=${frameId})\n`;
|
||||
} else {
|
||||
return `set_velocity(vx=${x}, vy=${y}, vz=${z}, yaw=float('nan'), frame_id=${frameId})\n`;
|
||||
}
|
||||
}
|
||||
|
||||
Blockly.Python.take_off = function(block) {
|
||||
simpleOffboard();
|
||||
|
||||
let z = Blockly.Python.valueToCode(block, 'ALT', Blockly.Python.ORDER_NONE);
|
||||
|
||||
if (block.getFieldValue('WAIT') == 'TRUE') {
|
||||
rosDefinitions.navigateWait = true;
|
||||
simpleOffboard();
|
||||
|
||||
return `navigate_wait(z=${z}, frame_id='body', auto_arm=True)\n`;
|
||||
} else {
|
||||
return `navigate(z=${z}, frame_id='body', auto_arm=True)\n`;
|
||||
}
|
||||
}
|
||||
|
||||
Blockly.Python.land = function(block) {
|
||||
simpleOffboard();
|
||||
|
||||
if (block.getFieldValue('WAIT') == 'TRUE') {
|
||||
rosDefinitions.landWait = true;
|
||||
simpleOffboard();
|
||||
|
||||
return `land_wait()\n`;
|
||||
} else {
|
||||
return 'land()\n';
|
||||
}
|
||||
}
|
||||
|
||||
Blockly.Python.angle = function(block) {
|
||||
// return [block.getFieldValue('ANGLE'), Blockly.Python.ORDER_UNARY_SIGN];
|
||||
Blockly.Python.definitions_['import_math'] = 'import math';
|
||||
return [`math.radians(${block.getFieldValue('ANGLE')})`, Blockly.Python.ORDER_FUNCTION_CALL];
|
||||
|
||||
}
|
||||
|
||||
Blockly.Python.set_yaw = function(block) {
|
||||
simpleOffboard();
|
||||
let yaw = Blockly.Python.valueToCode(block, 'YAW', Blockly.Python.ORDER_NONE);
|
||||
let frameId = buildFrameId(block);
|
||||
let code = `navigate(x=float('nan'), y=float('nan'), z=float('nan'), yaw=${yaw}, frame_id=${frameId})\n`;
|
||||
if (block.getFieldValue('WAIT') == 'TRUE') {
|
||||
rosDefinitions.waitYaw = true;
|
||||
simpleOffboard();
|
||||
code += 'wait_yaw()\n';
|
||||
}
|
||||
return code;
|
||||
}
|
||||
|
||||
Blockly.Python.wait_arrival = function(block) {
|
||||
rosDefinitions.waitArrival = true;
|
||||
simpleOffboard();
|
||||
return 'wait_arrival()\n';
|
||||
}
|
||||
|
||||
Blockly.Python.get_time = function(block) {
|
||||
initNode();
|
||||
return ['rospy.get_time()', Blockly.Python.ORDER_FUNCTION_CALL];
|
||||
}
|
||||
|
||||
Blockly.Python.arrived = function(block) {
|
||||
rosDefinitions.arrived = true;
|
||||
simpleOffboard();
|
||||
return ['arrived()', Blockly.Python.ORDER_FUNCTION_CALL];
|
||||
}
|
||||
|
||||
Blockly.Python.wait = function(block) {
|
||||
initNode();
|
||||
return `rospy.sleep(${Blockly.Python.valueToCode(block, 'TIME', Blockly.Python.ORDER_NONE)})\n`;
|
||||
}
|
||||
|
||||
Blockly.Python.setpoint = function(block) {
|
||||
var type = block.getFieldValue('TYPE');
|
||||
let frameId = buildFrameId(block);
|
||||
let vx = Blockly.Python.valueToCode(block, 'VX', Blockly.Python.ORDER_NONE);
|
||||
let vy = Blockly.Python.valueToCode(block, 'VY', Blockly.Python.ORDER_NONE);
|
||||
let vz = Blockly.Python.valueToCode(block, 'VZ', Blockly.Python.ORDER_NONE);
|
||||
let yaw = Blockly.Python.valueToCode(block, 'YAW', Blockly.Python.ORDER_NONE);
|
||||
let pitch = Blockly.Python.valueToCode(block, 'PITCH', Blockly.Python.ORDER_NONE);
|
||||
let roll = Blockly.Python.valueToCode(block, 'ROLL', Blockly.Python.ORDER_NONE);
|
||||
let thrust = Blockly.Python.valueToCode(block, 'THRUST', Blockly.Python.ORDER_NONE);
|
||||
|
||||
if (type == 'VELOCITY') {
|
||||
rosDefinitions.setVelocity = true;
|
||||
simpleOffboard();
|
||||
return `set_velocity(vx=${vx}, vy=${vy}, vz=${vz}, frame_id=${frameId}, yaw=float('nan'))\n`;
|
||||
} else if (type == 'ATTITUDE') {
|
||||
rosDefinitions.setAttitude = true;
|
||||
simpleOffboard();
|
||||
return `set_attitude(pitch=${pitch}, roll=${roll}, yaw=${yaw}, thrust=${thrust}, frame_id=${frameId})\n`;
|
||||
} else if (type == 'RATES') {
|
||||
rosDefinitions.setRates = true;
|
||||
simpleOffboard();
|
||||
return `set_rates(pitch_rate=${pitch}, roll_rate=${roll}, yaw_rate=${yaw}, thrust=${thrust})\n`;
|
||||
}
|
||||
}
|
||||
|
||||
Blockly.Python.get_position = function(block) {
|
||||
simpleOffboard();
|
||||
let frameId = buildFrameId(block);
|
||||
var code = `get_telemetry(${frameId}).${block.getFieldValue('FIELD').toLowerCase()}`;
|
||||
return [code, Blockly.Python.ORDER_FUNCTION_CALL];
|
||||
}
|
||||
|
||||
Blockly.Python.get_yaw = function(block) {
|
||||
simpleOffboard();
|
||||
Blockly.Python.definitions_['import_math'] = 'import math';
|
||||
let frameId = buildFrameId(block);
|
||||
var code = `math.degrees(get_telemetry(${frameId}).yaw)`;
|
||||
return [code, Blockly.Python.ORDER_FUNCTION_CALL];
|
||||
}
|
||||
|
||||
Blockly.Python.get_attitude = function(block) {
|
||||
simpleOffboard();
|
||||
Blockly.Python.definitions_['import_math'] = 'import math';
|
||||
var code = `math.degrees(get_telemetry().${block.getFieldValue('FIELD').toLowerCase()})`;
|
||||
return [code, Blockly.Python.ORDER_FUNCTION_CALL];
|
||||
}
|
||||
|
||||
Blockly.Python.distance = function(block) {
|
||||
rosDefinitions.distance = true;
|
||||
simpleOffboard();
|
||||
|
||||
let x = Blockly.Python.valueToCode(block, 'X', Blockly.Python.ORDER_NONE);
|
||||
let y = Blockly.Python.valueToCode(block, 'Y', Blockly.Python.ORDER_NONE);
|
||||
let z = Blockly.Python.valueToCode(block, 'Z', Blockly.Python.ORDER_NONE);
|
||||
let frameId = buildFrameId(block);
|
||||
|
||||
return [`get_distance(${x}, ${y}, ${z}, ${frameId})`, Blockly.Python.ORDER_FUNCTION_CALL]
|
||||
}
|
||||
|
||||
Blockly.Python.rangefinder_distance = function(block) {
|
||||
initNode();
|
||||
Blockly.Python.definitions_['import_range'] = 'from sensor_msgs.msg import Range';
|
||||
return [`rospy.wait_for_message('rangefinder/range', Range).range`, Blockly.Python.ORDER_FUNCTION_CALL]
|
||||
}
|
||||
|
||||
Blockly.Python.mode = function(block) {
|
||||
simpleOffboard();
|
||||
return [`get_telemetry().mode`, Blockly.Python.ORDER_FUNCTION_CALL]
|
||||
}
|
||||
|
||||
Blockly.Python.armed = function(block) {
|
||||
simpleOffboard();
|
||||
return [`get_telemetry().armed`, Blockly.Python.ORDER_FUNCTION_CALL]
|
||||
}
|
||||
|
||||
Blockly.Python.voltage = function(block) {
|
||||
simpleOffboard();
|
||||
var code = `get_telemetry().${block.getFieldValue('TYPE').toLowerCase()}`;
|
||||
return [code, Blockly.Python.ORDER_FUNCTION_CALL];
|
||||
}
|
||||
|
||||
function parseColor(color) {
|
||||
return {
|
||||
r: parseInt(color.substr(2, 2), 16),
|
||||
g: parseInt(color.substr(4, 2), 16),
|
||||
b: parseInt(color.substr(6, 2), 16)
|
||||
}
|
||||
}
|
||||
|
||||
const PARSE_COLOR = `def ${Blockly.Python.FUNCTION_NAME_PLACEHOLDER_}(color):
|
||||
return {'r': int(color[1:3], 16), 'g': int(color[3:5], 16), 'b': int(color[5:7], 16)}`;
|
||||
|
||||
// TODO: weird code with colour_rgb block
|
||||
Blockly.Python.set_effect = function(block) {
|
||||
rosDefinitions.setEffect = true;
|
||||
initNode();
|
||||
|
||||
var effect = block.getFieldValue('EFFECT').toLowerCase();
|
||||
|
||||
if (effect == 'rainbow' || effect == 'rainbow_fill') {
|
||||
return `set_effect(effect='${effect}')\n`;
|
||||
} else {
|
||||
let colorCode = Blockly.Python.valueToCode(block, 'COLOR', Blockly.Python.ORDER_NONE);
|
||||
|
||||
if (/^'(.*)'$/.test(colorCode)) { // is simple string
|
||||
let color = parseColor(colorCode);
|
||||
return `set_effect(effect='${effect}', r=${color.r}, g=${color.g}, b=${color.b})\n`;
|
||||
} else {
|
||||
let parseColor = Blockly.Python.provideFunction_('parse_color', [PARSE_COLOR]);
|
||||
return `set_effect(effect='${effect}', **${parseColor}(${colorCode}))\n`;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Blockly.Python.set_led = function(block) {
|
||||
rosDefinitions.setLeds = true;
|
||||
initNode();
|
||||
|
||||
var index = Blockly.Python.valueToCode(block, 'INDEX', Blockly.Python.ORDER_NONE);
|
||||
var colorCode = Blockly.Python.valueToCode(block, 'COLOR', Blockly.Python.ORDER_NONE);
|
||||
|
||||
if (/^'(.*)'$/.test(colorCode)) { // is simple string
|
||||
let color = parseColor(colorCode);
|
||||
return `set_leds([LEDState(index=${index}, r=${color.r}, g=${color.g}, b=${color.b})])\n`;
|
||||
} else {
|
||||
let parseColor = Blockly.Python.provideFunction_('parse_color', [PARSE_COLOR]);
|
||||
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() {
|
||||
Blockly.Python.definitions_['import_pigpio'] = 'import pigpio';
|
||||
Blockly.Python.definitions_['init_pigpio'] = 'pi = pigpio.pi()';
|
||||
}
|
||||
|
||||
const GPIO_READ = `\ndef gpio_read(pin):
|
||||
pi.set_mode(pin, pigpio.INPUT)
|
||||
return pi.read(pin)\n`;
|
||||
|
||||
const GPIO_WRITE = `\ndef gpio_write(pin, level):
|
||||
pi.set_mode(pin, pigpio.OUTPUT)
|
||||
pi.write(pin, level)\n`;
|
||||
|
||||
const SET_SERVO = `\ndef set_servo(pin, pwm):
|
||||
pi.set_mode(pin, pigpio.OUTPUT)
|
||||
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) {
|
||||
pigpio();
|
||||
Blockly.Python.definitions_['gpio_read'] = GPIO_READ;
|
||||
var pin = Blockly.Python.valueToCode(block, 'PIN', Blockly.Python.ORDER_NONE);
|
||||
return [`gpio_read(${pin})`, Blockly.Python.ORDER_FUNCTION_CALL];
|
||||
}
|
||||
|
||||
Blockly.Python.gpio_write = function(block) {
|
||||
pigpio();
|
||||
Blockly.Python.definitions_['gpio_write'] = GPIO_WRITE;
|
||||
var pin = Blockly.Python.valueToCode(block, 'PIN', Blockly.Python.ORDER_NONE);
|
||||
var level = Blockly.Python.valueToCode(block, 'LEVEL', Blockly.Python.ORDER_NONE);
|
||||
return `gpio_write(${pin}, ${level})\n`;
|
||||
}
|
||||
|
||||
Blockly.Python.set_servo = function(block) {
|
||||
pigpio();
|
||||
Blockly.Python.definitions_['set_servo'] = SET_SERVO;
|
||||
var pin = Blockly.Python.valueToCode(block, 'PIN', Blockly.Python.ORDER_NONE);
|
||||
var pwm = Blockly.Python.valueToCode(block, 'PWM', Blockly.Python.ORDER_NONE);
|
||||
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`;
|
||||
}
|
||||
69
clover_blocks/www/ros.js
Normal file
@@ -0,0 +1,69 @@
|
||||
/*
|
||||
* Copyright (C) 2020 Copter Express Technologies
|
||||
*
|
||||
* Author: Oleg Kalachev <okalachev@gmail.com>
|
||||
*
|
||||
* Distributed under MIT License (available at https://opensource.org/licenses/MIT).
|
||||
* The above copyright notice and this permission notice shall be included in all
|
||||
* copies or substantial portions of the Software.
|
||||
*/
|
||||
|
||||
var url = 'ws://' + location.hostname + ':9090';
|
||||
export var ros = new ROSLIB.Ros({ url });
|
||||
|
||||
ros.on('connection', function () {
|
||||
console.log('connection')
|
||||
document.body.classList.add('connected');
|
||||
});
|
||||
|
||||
ros.on('close', function () {
|
||||
console.log('close')
|
||||
document.body.classList.remove('connected');
|
||||
setTimeout(function() {
|
||||
ros.connect(url);
|
||||
}, 2000);
|
||||
});
|
||||
|
||||
ros.on('error', function(err) {
|
||||
});
|
||||
|
||||
export const namespace = '/';
|
||||
export const priv = namespace + 'clover_blocks/';
|
||||
|
||||
export var params = {}; // parameters storage
|
||||
|
||||
export function readParam(name, fromUrl, _default) {
|
||||
return new Promise(function(resolve, reject) {
|
||||
if (params[name] !== undefined) {
|
||||
resolve();
|
||||
return;
|
||||
}
|
||||
// read from url
|
||||
if (fromUrl && ((params[name] = new URL(window.location.href).searchParams.get(name)) !== null)) {
|
||||
resolve();
|
||||
return;
|
||||
}
|
||||
// read from ROS params
|
||||
new ROSLIB.Param({ ros: ros, name: priv + name }).get(function(val) {
|
||||
if (val === null) {
|
||||
if (_default === undefined) {
|
||||
alert('Cannot read required parameter ' + name);
|
||||
reject();
|
||||
} else {
|
||||
params[name] = _default;
|
||||
resolve();
|
||||
}
|
||||
return;
|
||||
}
|
||||
params[name] = val;
|
||||
resolve();
|
||||
})
|
||||
});
|
||||
}
|
||||
|
||||
|
||||
export var runService = new ROSLIB.Service({ ros: ros, name: priv + 'run', serviceType: 'clover_blocks/Run' });
|
||||
export var stopService = new ROSLIB.Service({ ros: ros, name: priv + 'stop', serviceType: 'std_srvs/Trigger' });
|
||||
export var loadService = new ROSLIB.Service({ ros: ros, name : priv + 'load', serviceType : 'clover_blocks/Load' });
|
||||
export var storeService = new ROSLIB.Service({ ros: ros, name : priv + 'store', serviceType : 'clover_blocks/Store' });
|
||||
export var landService = new ROSLIB.Service({ ros: ros, name : namespace + 'land', serviceType : 'std_srvs/Trigger' });
|
||||
4560
clover_blocks/www/roslib.js
vendored
Normal file
9
clover_description/CHANGELOG.rst
Normal file
@@ -0,0 +1,9 @@
|
||||
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||
Changelog for package clover_description
|
||||
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||
|
||||
0.21.1 (2020-11-17)
|
||||
-------------------
|
||||
* First release of clover_description package to ROS
|
||||
* Contributors: Alexey Rogachevskiy
|
||||
|
||||
10
clover_description/CMakeLists.txt
Normal file
@@ -0,0 +1,10 @@
|
||||
cmake_minimum_required(VERSION 3.0)
|
||||
project(clover_description)
|
||||
|
||||
find_package(catkin REQUIRED)
|
||||
|
||||
catkin_package()
|
||||
|
||||
install(DIRECTORY launch DESTINATION ${CATKIN_PACKAGE_SHARE_DESTINATION})
|
||||
install(DIRECTORY meshes DESTINATION ${CATKIN_PACKAGE_SHARE_DESTINATION})
|
||||
install(DIRECTORY urdf DESTINATION ${CATKIN_PACKAGE_SHARE_DESTINATION})
|
||||