Compare commits
74 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
fbc9c22cb3 | ||
|
|
32da94aeae | ||
|
|
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 |
@@ -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
|
||||
},
|
||||
|
||||
@@ -10,7 +10,7 @@ env:
|
||||
- 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:
|
||||
@@ -38,7 +38,7 @@ jobs:
|
||||
- cp images/*.zip imgcache
|
||||
after_success:
|
||||
- sudo chmod -R 777 *
|
||||
- cd images && zip ${IMAGE_NAME}.zip ${IMAGE_NAME} && stat --printf="Compressed image size:%s\n" ${IMAGE_NAME}.zip
|
||||
- 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"
|
||||
|
||||
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/clever4-front-white.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
|
||||
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -105,7 +105,7 @@ ${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
|
||||
|
||||
@@ -130,6 +130,9 @@ 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'
|
||||
|
||||
@@ -110,7 +110,6 @@ libffi-dev \
|
||||
monkey \
|
||||
pigpio python-pigpio python3-pigpio \
|
||||
i2c-tools \
|
||||
espeak espeak-data python-espeak \
|
||||
ntpdate \
|
||||
python-dev \
|
||||
python3-dev \
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -2,14 +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="$(eval ws281x and not simulator)">
|
||||
<param name="led_count" value="58"/>
|
||||
<param name="gpio_pin" value="21"/>
|
||||
<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"/>
|
||||
@@ -32,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>
|
||||
|
||||
@@ -9,6 +9,8 @@
|
||||
<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 -->
|
||||
|
||||
@@ -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>
|
||||
@@ -72,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
|
||||
@@ -122,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;
|
||||
@@ -486,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))
|
||||
@@ -513,6 +537,10 @@ bool serve(enum setpoint_type_t sp_type, float x, float y, float z, float vx, fl
|
||||
// Checks
|
||||
checkState();
|
||||
|
||||
if (auto_arm) {
|
||||
checkManualControl();
|
||||
}
|
||||
|
||||
// default frame is local frame
|
||||
if (frame_id.empty())
|
||||
frame_id = local_frame;
|
||||
@@ -834,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);
|
||||
@@ -843,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));
|
||||
@@ -860,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
|
||||
|
||||
@@ -30,7 +30,9 @@ The frontend files are located in [`www`](./www/) subdirectory. The frontend app
|
||||
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:
|
||||
|
||||
|
||||
@@ -29,7 +29,7 @@
|
||||
</value>
|
||||
<value name="Z">
|
||||
<shadow type="math_number" id="n0ULZn64%k.:,l(,D?TZ">
|
||||
<field name="NUM">0</field>
|
||||
<field name="NUM">1</field>
|
||||
</shadow>
|
||||
</value>
|
||||
<value name="ID">
|
||||
|
||||
@@ -1,106 +1,91 @@
|
||||
<xml xmlns="https://developers.google.com/blockly/xml">
|
||||
<variables>
|
||||
<variable id="_{V-S5HPBUl]CcJkL1Jw">led_count</variable>
|
||||
</variables>
|
||||
<block type="variables_set" id="{)^J~:UMX%D;RWvztWLN" x="113" y="87">
|
||||
<field name="VAR" id="_{V-S5HPBUl]CcJkL1Jw">led_count</field>
|
||||
<value name="VALUE">
|
||||
<block type="math_number" id="V_W$3,VFwZjcc|?|1o`l">
|
||||
<field name="NUM">58</field>
|
||||
<block 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>
|
||||
<next>
|
||||
<block type="controls_whileUntil" id="U1it{GcGuSS:=[xiwZr1">
|
||||
<field name="MODE">WHILE</field>
|
||||
<value name="BOOL">
|
||||
<block type="logic_boolean" id="]7ZDRwde}/RqjQCX}aVW">
|
||||
<field name="BOOL">TRUE</field>
|
||||
</block>
|
||||
<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>
|
||||
<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>
|
||||
<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>
|
||||
</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>
|
||||
<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="AI6PZBd`]_Z%_~4c-%dB">
|
||||
<field name="OP">MULTIPLY</field>
|
||||
<block type="math_arithmetic" id="-haE#:,cg{-J=NZERA;F">
|
||||
<field name="OP">DIVIDE</field>
|
||||
<value name="A">
|
||||
<shadow type="math_number" id="|p}X]`SedK3).F/;}NlB">
|
||||
<shadow type="math_number" id="::st;ot}[r]csqceURu*">
|
||||
<field name="NUM">1</field>
|
||||
</shadow>
|
||||
<block type="math_arithmetic" id="-haE#:,cg{-J=NZERA;F">
|
||||
<field name="OP">DIVIDE</field>
|
||||
<block type="math_arithmetic" id="a%+LN)F~=Igg+,p02[qo">
|
||||
<field name="OP">ADD</field>
|
||||
<value name="A">
|
||||
<shadow type="math_number" id="::st;ot}[r]csqceURu*">
|
||||
<shadow type="math_number" id="*yIGN((y)/^z0:f5:VDw">
|
||||
<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>
|
||||
<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="Wo1/ZCeir,u6/.e1H+BB">
|
||||
<field name="NUM">360</field>
|
||||
<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="jENTcXz0C5/=)Xpd!}LL">
|
||||
<field name="NUM">1</field>
|
||||
<shadow type="math_number" id="Wo1/ZCeir,u6/.e1H+BB">
|
||||
<field name="NUM">360</field>
|
||||
</shadow>
|
||||
<block type="variables_get" id="Ko,`n=i88FY~`YbQLA?[">
|
||||
<field name="VAR" id="_{V-S5HPBUl]CcJkL1Jw">led_count</field>
|
||||
</block>
|
||||
</value>
|
||||
</block>
|
||||
</value>
|
||||
<value name="COLOR">
|
||||
<shadow type="colour_picker" id="+vw3bff.5c[=_w,Xm^C(">
|
||||
<field name="COLOUR">#3366ff</field>
|
||||
<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>
|
||||
<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>
|
||||
</next>
|
||||
</block>
|
||||
</next>
|
||||
</statement>
|
||||
</block>
|
||||
</xml>
|
||||
</xml>
|
||||
@@ -1,5 +1,13 @@
|
||||
#!/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
|
||||
|
||||
@@ -1,3 +1,13 @@
|
||||
/*
|
||||
* 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;
|
||||
@@ -343,6 +353,17 @@ Blockly.Blocks['set_effect'] = {
|
||||
}
|
||||
};
|
||||
|
||||
Blockly.Blocks['led_count'] = {
|
||||
init: function () {
|
||||
this.appendDummyInput()
|
||||
.appendField("LED count");
|
||||
this.setOutput(true, "Number");
|
||||
this.setColour(COLOR_LED);
|
||||
this.setTooltip("Returns the number of LEDs (configured in led.launch).");
|
||||
this.setHelpUrl(DOCS_URL + '#' + this.type);
|
||||
}
|
||||
};
|
||||
|
||||
Blockly.Blocks['take_off'] = {
|
||||
init: function () {
|
||||
this.appendValueInput("ALT")
|
||||
@@ -525,7 +546,7 @@ Blockly.Blocks['gpio_read'] = {
|
||||
this.setOutput(true, "Boolean");
|
||||
this.setColour(COLOR_GPIO);
|
||||
this.setTooltip("Returns if there is voltage on a GPIO pin.");
|
||||
this.setHelpUrl(DOCS_URL + '#' + this.type);
|
||||
this.setHelpUrl(DOCS_URL + '#GPIO');
|
||||
}
|
||||
};
|
||||
|
||||
@@ -542,7 +563,7 @@ Blockly.Blocks['gpio_write'] = {
|
||||
this.setPreviousStatement(true, null);
|
||||
this.setNextStatement(true, null);
|
||||
this.setTooltip("Set GPIO pin level.");
|
||||
this.setHelpUrl(DOCS_URL + '#' + this.type);
|
||||
this.setHelpUrl(DOCS_URL + '#GPIO');
|
||||
}
|
||||
};
|
||||
|
||||
@@ -558,7 +579,24 @@ Blockly.Blocks['set_servo'] = {
|
||||
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 ms.");
|
||||
this.setHelpUrl(DOCS_URL + '#' + this.type);
|
||||
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');
|
||||
}
|
||||
};
|
||||
|
||||
@@ -106,6 +106,7 @@
|
||||
<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">
|
||||
@@ -119,6 +120,10 @@
|
||||
<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">
|
||||
|
||||
@@ -1,3 +1,13 @@
|
||||
/*
|
||||
* 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';
|
||||
@@ -29,7 +39,9 @@ var workspace = Blockly.inject('blockly', {
|
||||
function readParams() {
|
||||
return Promise.all([
|
||||
ros.readParam('navigate_tolerance', true, 0.2),
|
||||
ros.readParam('sleep_time', true, 0.2)
|
||||
ros.readParam('yaw_tolerance', true, 20),
|
||||
ros.readParam('sleep_time', true, 0.2),
|
||||
ros.readParam('confirm_run', true, true),
|
||||
]);
|
||||
}
|
||||
|
||||
@@ -97,7 +109,7 @@ new ROSLIB.Topic({ ros: ros.ros, name: ros.priv + 'prompt', messageType: 'clover
|
||||
name: ros.priv + 'input/' + msg.id,
|
||||
messageType: 'std_msgs/String',
|
||||
latch: true
|
||||
}).publish(new ROSLIB.Message({ data: response }));
|
||||
}).publish(new ROSLIB.Message({ data: response || '' }));
|
||||
});
|
||||
|
||||
window.stopProgram = function() {
|
||||
@@ -113,7 +125,7 @@ ros.ros.on('close', update);
|
||||
ready.then(() => runButton.disabled = false);
|
||||
|
||||
window.runProgram = function() {
|
||||
if (!confirm('Run program?')) return;
|
||||
if (ros.params.confirm_run && !confirm('Run program?')) return;
|
||||
|
||||
runRequest = true;
|
||||
update();
|
||||
|
||||
@@ -1,3 +1,13 @@
|
||||
/*
|
||||
* 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.
|
||||
@@ -5,17 +15,12 @@ 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');
|
||||
Blockly.Python.addReservedWords('SetLEDEffect,set_effect,led_count,get_led_count');
|
||||
Blockly.Python.addReservedWords('SetLEDs,LEDState,set_leds');
|
||||
|
||||
// TODO: parametrize
|
||||
const navigate_tolerance = 0.2;
|
||||
const sleep_time = 0.2;
|
||||
|
||||
const IMPORT_SRV = `from clover import srv
|
||||
from std_srvs.srv import Trigger`;
|
||||
|
||||
// TODO: tolerance to parameters
|
||||
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)
|
||||
|
||||
@@ -33,15 +38,13 @@ const LAND_WAIT = () => `\ndef land_wait():
|
||||
while get_telemetry().armed:
|
||||
rospy.sleep(${params.sleep_time})\n`;
|
||||
|
||||
// TODO: tolerance to parameters
|
||||
const WAIT_YAW = () => `\ndef wait_yaw():
|
||||
while not rospy.is_shutdown():
|
||||
telem = get_telemetry(frame_id='navigate_target')
|
||||
if abs(telem.yaw) < math.radians(20):
|
||||
if abs(telem.yaw) < math.radians(${params.yaw_tolerance}):
|
||||
return
|
||||
rospy.sleep(${params.sleep_time})\n`;
|
||||
|
||||
// TODO: tolerance to parameters
|
||||
const WAIT_ARRIVAL = () => `\ndef wait_arrival():
|
||||
while not rospy.is_shutdown():
|
||||
telem = get_telemetry(frame_id='navigate_target')
|
||||
@@ -49,7 +52,6 @@ const WAIT_ARRIVAL = () => `\ndef wait_arrival():
|
||||
return
|
||||
rospy.sleep(${params.sleep_time})\n`;
|
||||
|
||||
// TODO: tolerance to parameters
|
||||
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`
|
||||
@@ -85,6 +87,9 @@ function generateROSDefinitions() {
|
||||
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();
|
||||
@@ -389,26 +394,45 @@ Blockly.Python.set_led = function(block) {
|
||||
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`;
|
||||
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`;
|
||||
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`;
|
||||
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`;
|
||||
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();
|
||||
@@ -432,3 +456,11 @@ Blockly.Python.set_servo = function(block) {
|
||||
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`;
|
||||
}
|
||||
|
||||
@@ -1,3 +1,13 @@
|
||||
/*
|
||||
* 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 });
|
||||
|
||||
|
||||
BIN
docs/assets/assembling_soldering_clever_4/coex_fc_1.png
Normal file
|
After Width: | Height: | Size: 344 KiB |
BIN
docs/assets/assembling_soldering_clever_4/coex_fc_2.png
Normal file
|
After Width: | Height: | Size: 340 KiB |
BIN
docs/assets/assembling_soldering_clever_4/coex_fc_3.png
Normal file
|
After Width: | Height: | Size: 401 KiB |
BIN
docs/assets/assembling_soldering_clever_4/coex_pix_1.png
Normal file
|
After Width: | Height: | Size: 345 KiB |
BIN
docs/assets/assembling_soldering_clever_4/coex_pix_2.png
Normal file
|
After Width: | Height: | Size: 419 KiB |
BIN
docs/assets/assembling_soldering_clever_4/esc_1.png
Normal file
|
After Width: | Height: | Size: 313 KiB |
BIN
docs/assets/assembling_soldering_clever_4/esc_10.png
Normal file
|
After Width: | Height: | Size: 218 KiB |
BIN
docs/assets/assembling_soldering_clever_4/esc_11.png
Normal file
|
After Width: | Height: | Size: 549 KiB |
BIN
docs/assets/assembling_soldering_clever_4/esc_2.png
Normal file
|
After Width: | Height: | Size: 302 KiB |
BIN
docs/assets/assembling_soldering_clever_4/esc_3.png
Normal file
|
After Width: | Height: | Size: 331 KiB |
BIN
docs/assets/assembling_soldering_clever_4/esc_4.png
Normal file
|
After Width: | Height: | Size: 466 KiB |
BIN
docs/assets/assembling_soldering_clever_4/esc_5.png
Normal file
|
After Width: | Height: | Size: 469 KiB |
BIN
docs/assets/assembling_soldering_clever_4/esc_6.png
Normal file
|
After Width: | Height: | Size: 330 KiB |
BIN
docs/assets/assembling_soldering_clever_4/esc_7.png
Normal file
|
After Width: | Height: | Size: 472 KiB |
BIN
docs/assets/assembling_soldering_clever_4/esc_8.png
Normal file
|
After Width: | Height: | Size: 324 KiB |
BIN
docs/assets/assembling_soldering_clever_4/esc_9.png
Normal file
|
After Width: | Height: | Size: 461 KiB |
BIN
docs/assets/assembling_soldering_clever_4/fc_connection_1.png
Normal file
|
After Width: | Height: | Size: 256 KiB |
BIN
docs/assets/assembling_soldering_clever_4/fc_connection_2.png
Normal file
|
After Width: | Height: | Size: 456 KiB |
BIN
docs/assets/assembling_soldering_clever_4/fc_connection_3.png
Normal file
|
After Width: | Height: | Size: 479 KiB |
BIN
docs/assets/assembling_soldering_clever_4/fc_connection_4.png
Normal file
|
After Width: | Height: | Size: 337 KiB |
BIN
docs/assets/assembling_soldering_clever_4/fc_connection_5.png
Normal file
|
After Width: | Height: | Size: 338 KiB |
BIN
docs/assets/assembling_soldering_clever_4/frame_1.png
Normal file
|
After Width: | Height: | Size: 226 KiB |
BIN
docs/assets/assembling_soldering_clever_4/frame_2.png
Normal file
|
After Width: | Height: | Size: 238 KiB |
BIN
docs/assets/assembling_soldering_clever_4/frame_3.png
Normal file
|
After Width: | Height: | Size: 228 KiB |
BIN
docs/assets/assembling_soldering_clever_4/frame_4.png
Normal file
|
After Width: | Height: | Size: 258 KiB |
BIN
docs/assets/assembling_soldering_clever_4/frame_5.png
Normal file
|
After Width: | Height: | Size: 112 KiB |
BIN
docs/assets/assembling_soldering_clever_4/frame_6.png
Normal file
|
After Width: | Height: | Size: 253 KiB |
BIN
docs/assets/assembling_soldering_clever_4/frame_7.png
Normal file
|
After Width: | Height: | Size: 257 KiB |
BIN
docs/assets/assembling_soldering_clever_4/guard_1.png
Normal file
|
After Width: | Height: | Size: 134 KiB |
BIN
docs/assets/assembling_soldering_clever_4/guard_2.png
Normal file
|
After Width: | Height: | Size: 172 KiB |
BIN
docs/assets/assembling_soldering_clever_4/guard_3.png
Normal file
|
After Width: | Height: | Size: 315 KiB |
BIN
docs/assets/assembling_soldering_clever_4/guard_4.png
Normal file
|
After Width: | Height: | Size: 564 KiB |
BIN
docs/assets/assembling_soldering_clever_4/guard_5.png
Normal file
|
After Width: | Height: | Size: 593 KiB |
BIN
docs/assets/assembling_soldering_clever_4/guard_6.png
Normal file
|
After Width: | Height: | Size: 313 KiB |
BIN
docs/assets/assembling_soldering_clever_4/led_1.png
Normal file
|
After Width: | Height: | Size: 70 KiB |
BIN
docs/assets/assembling_soldering_clever_4/led_2.png
Normal file
|
After Width: | Height: | Size: 175 KiB |
BIN
docs/assets/assembling_soldering_clever_4/led_3.png
Normal file
|
After Width: | Height: | Size: 116 KiB |
BIN
docs/assets/assembling_soldering_clever_4/led_4.png
Normal file
|
After Width: | Height: | Size: 437 KiB |
BIN
docs/assets/assembling_soldering_clever_4/led_5.png
Normal file
|
After Width: | Height: | Size: 376 KiB |
BIN
docs/assets/assembling_soldering_clever_4/led_6.png
Normal file
|
After Width: | Height: | Size: 498 KiB |
BIN
docs/assets/assembling_soldering_clever_4/led_7.png
Normal file
|
After Width: | Height: | Size: 574 KiB |
BIN
docs/assets/assembling_soldering_clever_4/led_8.png
Normal file
|
After Width: | Height: | Size: 715 KiB |
BIN
docs/assets/assembling_soldering_clever_4/led_9.png
Normal file
|
After Width: | Height: | Size: 402 KiB |
BIN
docs/assets/assembling_soldering_clever_4/motor_1.png
Normal file
|
After Width: | Height: | Size: 211 KiB |
BIN
docs/assets/assembling_soldering_clever_4/motor_2.png
Normal file
|
After Width: | Height: | Size: 197 KiB |
BIN
docs/assets/assembling_soldering_clever_4/raspberry_1.png
Normal file
|
After Width: | Height: | Size: 101 KiB |
BIN
docs/assets/assembling_soldering_clever_4/raspberry_10.png
Normal file
|
After Width: | Height: | Size: 75 KiB |
BIN
docs/assets/assembling_soldering_clever_4/raspberry_11.png
Normal file
|
After Width: | Height: | Size: 62 KiB |
BIN
docs/assets/assembling_soldering_clever_4/raspberry_12.png
Normal file
|
After Width: | Height: | Size: 71 KiB |
BIN
docs/assets/assembling_soldering_clever_4/raspberry_13.png
Normal file
|
After Width: | Height: | Size: 35 KiB |
BIN
docs/assets/assembling_soldering_clever_4/raspberry_14.png
Normal file
|
After Width: | Height: | Size: 118 KiB |
BIN
docs/assets/assembling_soldering_clever_4/raspberry_15.png
Normal file
|
After Width: | Height: | Size: 301 KiB |
BIN
docs/assets/assembling_soldering_clever_4/raspberry_16.png
Normal file
|
After Width: | Height: | Size: 371 KiB |
BIN
docs/assets/assembling_soldering_clever_4/raspberry_17.png
Normal file
|
After Width: | Height: | Size: 362 KiB |
BIN
docs/assets/assembling_soldering_clever_4/raspberry_18.png
Normal file
|
After Width: | Height: | Size: 335 KiB |
BIN
docs/assets/assembling_soldering_clever_4/raspberry_2.png
Normal file
|
After Width: | Height: | Size: 248 KiB |
BIN
docs/assets/assembling_soldering_clever_4/raspberry_3.png
Normal file
|
After Width: | Height: | Size: 263 KiB |
BIN
docs/assets/assembling_soldering_clever_4/raspberry_4.png
Normal file
|
After Width: | Height: | Size: 271 KiB |
BIN
docs/assets/assembling_soldering_clever_4/raspberry_5.png
Normal file
|
After Width: | Height: | Size: 300 KiB |
BIN
docs/assets/assembling_soldering_clever_4/raspberry_6.png
Normal file
|
After Width: | Height: | Size: 334 KiB |
BIN
docs/assets/assembling_soldering_clever_4/raspberry_7.png
Normal file
|
After Width: | Height: | Size: 27 KiB |
BIN
docs/assets/assembling_soldering_clever_4/raspberry_8.png
Normal file
|
After Width: | Height: | Size: 18 KiB |
BIN
docs/assets/assembling_soldering_clever_4/raspberry_9.png
Normal file
|
After Width: | Height: | Size: 77 KiB |
BIN
docs/assets/clover4_sphere_guard.png
Normal file
|
After Width: | Height: | Size: 548 KiB |
BIN
docs/assets/coex_pix/coexpix-bottom-rev1.2.png
Normal file
|
After Width: | Height: | Size: 125 KiB |
|
Before Width: | Height: | Size: 368 KiB After Width: | Height: | Size: 368 KiB |
BIN
docs/assets/coex_pix/coexpix-top-rev1.2.png
Normal file
|
After Width: | Height: | Size: 133 KiB |
|
Before Width: | Height: | Size: 405 KiB After Width: | Height: | Size: 405 KiB |
21446
docs/assets/dxf/4.2/deck_mount.dxf
Normal file
BIN
docs/assets/dxf/4.2/deck_mount.png
Normal file
|
After Width: | Height: | Size: 171 KiB |
18312
docs/assets/dxf/4.2/deck_mount_small.dxf
Normal file
BIN
docs/assets/dxf/4.2/deck_mount_small.png
Normal file
|
After Width: | Height: | Size: 112 KiB |
20006
docs/assets/dxf/4.2/grab_deck.dxf
Normal file
BIN
docs/assets/dxf/4.2/grab_deck.png
Normal file
|
After Width: | Height: | Size: 151 KiB |
15620
docs/assets/dxf/4.2/led_mount_plate.dxf
Normal file
BIN
docs/assets/dxf/4.2/led_mount_plate.png
Normal file
|
After Width: | Height: | Size: 5.5 KiB |
15252
docs/assets/dxf/4.2/prop_guard.dxf
Normal file
BIN
docs/assets/dxf/4.2/prop_guard.png
Normal file
|
After Width: | Height: | Size: 29 KiB |