Merge branch 'master' into raspios_64bit
@@ -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="58"/>
|
||||
<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"/>
|
||||
|
||||
@@ -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>
|
||||
@@ -74,7 +75,7 @@ ros::Duration global_position_timeout;
|
||||
ros::Duration battery_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 +123,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 +488,18 @@ void publishSetpoint(const ros::TimerEvent& event)
|
||||
publish(event.current_real);
|
||||
}
|
||||
|
||||
inline void checkKillSwitch()
|
||||
{
|
||||
if (!TIMEOUT(manual_control, state_timeout))
|
||||
throw std::runtime_error("Manual control timeout, can't check kill switch status");
|
||||
|
||||
const int KILL_SWITCH_BIT = 12; // https://github.com/PX4/Firmware/blob/c302514a0809b1765fafd13c014d705446ae1113/src/modules/mavlink/mavlink_messages.cpp#L3975
|
||||
bool kill_switch = manual_control.buttons & (1 << KILL_SWITCH_BIT);
|
||||
|
||||
if (kill_switch)
|
||||
throw std::runtime_error("Kill switch is on");
|
||||
}
|
||||
|
||||
inline void checkState()
|
||||
{
|
||||
if (TIMEOUT(state, state_timeout))
|
||||
@@ -513,6 +527,10 @@ bool serve(enum setpoint_type_t sp_type, float x, float y, float z, float vx, fl
|
||||
// Checks
|
||||
checkState();
|
||||
|
||||
if (auto_arm && check_kill_switch) {
|
||||
checkKillSwitch();
|
||||
}
|
||||
|
||||
// default frame is local frame
|
||||
if (frame_id.empty())
|
||||
frame_id = local_frame;
|
||||
@@ -834,6 +852,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);
|
||||
@@ -860,6 +879,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:
|
||||
|
||||
|
||||
@@ -39,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),
|
||||
]);
|
||||
}
|
||||
|
||||
@@ -107,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() {
|
||||
@@ -123,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();
|
||||
|
||||
@@ -38,11 +38,10 @@ 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`;
|
||||
|
||||
|
||||
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 |
15648
docs/assets/dxf/4.2/prop_guard_mount.dxf
Normal file
BIN
docs/assets/dxf/4.2/prop_guard_mount.png
Normal file
|
After Width: | Height: | Size: 50 KiB |
15904
docs/assets/dxf/4.2/small_leg.dxf
Normal file
BIN
docs/assets/dxf/4.2/small_leg.png
Normal file
|
After Width: | Height: | Size: 82 KiB |
@@ -1,6 +1,6 @@
|
||||
# Working with a LED strip
|
||||
|
||||
> **Note** Documentation for the [image](image.md) versions, starting with **0.20**. For older versions refer to [documentation for version **0.19**](https://github.com/CopterExpress/clover/blob/v0.19/docs/en/leds.md).
|
||||
> **Note** Documentation for the [image](image.md) versions, starting with **0.21**. For older versions refer to [documentation for version **0.20**](https://github.com/CopterExpress/clover/blob/v0.20/docs/en/leds.md).
|
||||
|
||||
Clover drone kits contain addressable LED strips based on *ws281x* drivers. Each LED may be set to any one of 16 million possible colors (each color is encoded by a 24-bit number). This allows making the Clover flight more spectacular, as well as show flight modes, display stages of current user program, and notify the pilot of other events.
|
||||
|
||||
@@ -26,8 +26,8 @@ Our [Raspberry Pi image](image.md) contains preinstalled modules for interfacing
|
||||
3. Configure the *ws281x* parameters in `~/catkin_ws/src/clover/clover/launch/led.launch`. Change the number of addressable LEDs and the GPIO pin used for control to match your configuration:
|
||||
|
||||
```xml
|
||||
<param name="led_count" value="30"/> <!-- Number of LEDs in the strip -->
|
||||
<param name="gpio_pin" value="21"/> <!-- GPIO data pin -->
|
||||
<arg name="led_count" default="58"/> <!-- Number of LEDs in the strip -->
|
||||
<arg name="gpio_pin" default="21"/> <!-- GPIO data pin -->
|
||||
```
|
||||
|
||||
High-level interface allows changing current effect (or animation) on the strip. It is exposed as the `/led/set_effect` service. It has the following arguments:
|
||||
|
||||
@@ -2,6 +2,84 @@
|
||||
|
||||
This page contains models and drawings of some of the drone parts. They can be used for 3D printing and/or laser cutting replacement parts.
|
||||
|
||||
## Clover 4.2
|
||||
|
||||
### Milling
|
||||
|
||||
<table>
|
||||
<tr><th width=150>Preview</th><th>Part</th><th width=1>File</th></tr>
|
||||
<tr>
|
||||
<td><img src="../assets/dxf/4.2/deck_mount.png"></td>
|
||||
<td>
|
||||
<b>Deck mount</b>.<br>
|
||||
Function: Deck for installing battery and Raspberry Pi<br>
|
||||
Material: Monolithic polycarbonate 2mm.<br>
|
||||
Quantity: 1 pcs.
|
||||
</td>
|
||||
<td><a href="https://github.com/CopterExpress/clover/raw/master/docs/assets/dxf/4.2/deck_mount.dxf"><code>deck_mount.dxf</code></a></td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td><img src="../assets/dxf/4.2/deck_mount_small.png"></td>
|
||||
<td>
|
||||
<b>Deck mount small</b>.<br>
|
||||
Function: Deck for mounting FPV cameras and mounting stiffening plates.<br>
|
||||
Material: Monolithic polycarbonate 2mm.<br>
|
||||
Quantity: 1 pcs.
|
||||
</td>
|
||||
<td><a href="https://github.com/CopterExpress/clover/raw/master/docs/assets/dxf/4.2/deck_mount_small.dxf"><code>deck_mount_small.dxf</code></a></td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td><img src="../assets/dxf/4.2/grab_deck.png"></td>
|
||||
<td>
|
||||
<b>Grab deck</b>.<br>
|
||||
Function: Deck for installing grippers and external peripherals (camera, rangefinder).<br>
|
||||
Material: Monolithic polycarbonate 2mm.<br>
|
||||
Quantity: 1 pcs.
|
||||
</td>
|
||||
<td><a href="https://github.com/CopterExpress/clover/raw/master/docs/assets/dxf/4.2/grab_deck.dxf"><code>grab_deck.dxf</code></a></td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td><img src="../assets/dxf/4.2/led_mount_plate.png"></td>
|
||||
<td>
|
||||
<b>Led mount plate</b>.<br>
|
||||
Function: Fixing the LED strip.<br>
|
||||
Material: Monolithic polycarbonate 2mm.<br>
|
||||
Quantity: 1 pcs.
|
||||
</td>
|
||||
<td><a href="https://github.com/CopterExpress/clover/raw/master/docs/assets/dxf/4.2/led_mount_plate.dxf"><code>led_mount_plate.dxf</code></a></td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td><img src="../assets/dxf/4.2/prop_guard.png"></td>
|
||||
<td>
|
||||
<b>Prop guard</b>.<br>
|
||||
Function: Prevent damage of propellers.<br>
|
||||
Material: Monolithic polycarbonate 2mm.<br>
|
||||
Quantity: 4 pcs.
|
||||
</td>
|
||||
<td><a href="https://github.com/CopterExpress/clover/raw/master/docs/assets/dxf/4.2/prop_guard.dxf"><code>prop_guard.dxf</code></a></td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td><img src="../assets/dxf/4.2/prop_guard_mount.png"></td>
|
||||
<td>
|
||||
<b>Prop guard mount</b>.<br>
|
||||
Function: Arc for securing the guard.<br>
|
||||
Material: Monolithic polycarbonate 2mm.<br>
|
||||
Quantity: 2 pcs.
|
||||
</td>
|
||||
<td><a href="https://github.com/CopterExpress/clover/raw/master/docs/assets/dxf/4.2/prop_guard_mount.dxf"><code>prop_guard_mount.dxf</code></a></td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td><img src="../assets/dxf/4.2/small_leg.png"></td>
|
||||
<td>
|
||||
<b>Small leg</b>.<br>
|
||||
Function: Standard footing element.<br>
|
||||
Material: Monolithic polycarbonate 2mm.<br>
|
||||
Quantity: 2 pcs.
|
||||
</td>
|
||||
<td><a href="https://github.com/CopterExpress/clover/raw/master/docs/assets/dxf/4.2/small_leg.dxf"><code>small_leg.dxf</code></a></td>
|
||||
</tr>
|
||||
</table>
|
||||
|
||||
## Clover 4
|
||||
|
||||
### 3D print
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
# Работа со светодиодной лентой
|
||||
|
||||
> **Note** Документация для версий [образа](image.md), начиная с **0.20**. Для более ранних версий см. [документацию для версии **0.19**](https://github.com/CopterExpress/clover/blob/v0.19/docs/ru/leds.md).
|
||||
> **Note** Документация для версий [образа](image.md), начиная с **0.21**. Для более ранних версий см. [документацию для версии **0.20**](https://github.com/CopterExpress/clover/blob/v0.20/docs/ru/leds.md).
|
||||
|
||||
Адресуемая RGB-светодиодная лента типа *ws281x*, которая входит в наборы "Клевер", позволяет выставлять произвольные 24-битные цвета на каждый из отдельных светодиодов. Это позволяет сделать полет Клевера более ярким, а также визуально получать информацию о полетных режимах, этапе выполнения пользовательской программы и других событиях.
|
||||
|
||||
@@ -26,8 +26,8 @@
|
||||
3. Настройте параметры подключения ленты *ws281x* в файле `~/catkin_ws/src/clover/clover/launch/led.launch`. Необходимо ввести верное количество светодиодов в ленте и GPIO-пин, использованный для подключения (если он отличается от *GPIO21*):
|
||||
|
||||
```xml
|
||||
<param name="led_count" value="30"/> <!-- количество светодиодов в ленте -->
|
||||
<param name="gpio_pin" value="21"/> <!-- GPIO-пин для подключения -->
|
||||
<arg name="led_count" default="58"/> <!-- количество светодиодов в ленте -->
|
||||
<arg name="gpio_pin" default="21"/> <!-- GPIO-пин для подключения -->
|
||||
```
|
||||
|
||||
Высокоуровневое управления лентой позволяет управлять текущим эффектом (анимацией) на ленте. Для этого используется ROS-сервис `/led/set_effect`. Параметры сервиса:
|
||||
|
||||
@@ -2,6 +2,84 @@
|
||||
|
||||
На этой странице представлены CAD-модели некоторых деталей квадрокоптеров Клевер.
|
||||
|
||||
## Клевер 4.2
|
||||
|
||||
### Фрезеровка
|
||||
|
||||
<table>
|
||||
<tr><th width=150>Изображение</th><th>Деталь</th><th width=1>Файл</th></tr>
|
||||
<tr>
|
||||
<td><img src="../assets/dxf/4.2/deck_mount.png"></td>
|
||||
<td>
|
||||
<b>Дека монтажная</b>.<br>
|
||||
Функция: Дека для установки АКБ и Raspberry Pi.<br>
|
||||
Материал: Монолитный поликарбонат 2мм.<br>
|
||||
Количество: 1 шт.
|
||||
</td>
|
||||
<td><a href="https://github.com/CopterExpress/clover/raw/master/docs/assets/dxf/4.2/deck_mount.dxf"><code>deck_mount.dxf</code></a></td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td><img src="../assets/dxf/4.2/deck_mount_small.png"></td>
|
||||
<td>
|
||||
<b>Дека монтажная малая</b>.<br>
|
||||
Функция: Дека для установки FPV камеры и крепления пластин жесткости.<br>
|
||||
Материал: Монолитный поликарбонат 2мм.<br>
|
||||
Количество: 1 шт.
|
||||
</td>
|
||||
<td><a href="https://github.com/CopterExpress/clover/raw/master/docs/assets/dxf/4.2/deck_mount_small.dxf"><code>deck_mount_small.dxf</code></a></td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td><img src="../assets/dxf/4.2/grab_deck.png"></td>
|
||||
<td>
|
||||
<b>Дека захвата</b>.<br>
|
||||
Функция: Дека для установки захватов и внешней переферии(камера, дальномер).<br>
|
||||
Материал: Монолитный поликарбонат 2мм.<br>
|
||||
Количество: 1 шт.
|
||||
</td>
|
||||
<td><a href="https://github.com/CopterExpress/clover/raw/master/docs/assets/dxf/4.2/grab_deck.dxf"><code>grab_deck.dxf</code></a></td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td><img src="../assets/dxf/4.2/led_mount_plate.png"></td>
|
||||
<td>
|
||||
<b>Пластина для LED</b>.<br>
|
||||
Функция: Крепление светодиодной ленты.<br>
|
||||
Материал: Монолитный поликарбонат 2мм.<br>
|
||||
Количество: 1 шт.
|
||||
</td>
|
||||
<td><a href="https://github.com/CopterExpress/clover/raw/master/docs/assets/dxf/4.2/led_mount_plate.dxf"><code>led_mount_plate.dxf</code></a></td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td><img src="../assets/dxf/4.2/prop_guard.png"></td>
|
||||
<td>
|
||||
<b>Дуга</b>.<br>
|
||||
Функция: Предотвращение повреждения пропеллеров.<br>
|
||||
Материал: Монолитный поликарбонат 2мм.<br>
|
||||
Количество: 4 шт.
|
||||
</td>
|
||||
<td><a href="https://github.com/CopterExpress/clover/raw/master/docs/assets/dxf/4.2/prop_guard.dxf"><code>prop_guard.dxf</code></a></td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td><img src="../assets/dxf/4.2/prop_guard_mount.png"></td>
|
||||
<td>
|
||||
<b>Дуга монтажная</b>.<br>
|
||||
Функция: Дуга для закрепления контура защиты.<br>
|
||||
Материал: Монолитный поликарбонат 2мм.<br>
|
||||
Количество: 2 шт.
|
||||
</td>
|
||||
<td><a href="https://github.com/CopterExpress/clover/raw/master/docs/assets/dxf/4.2/prop_guard_mount.dxf"><code>prop_guard_mount.dxf</code></a></td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td><img src="../assets/dxf/4.2/small_leg.png"></td>
|
||||
<td>
|
||||
<b>Ножка маленькая</b>.<br>
|
||||
Функция: Стандартный опорный элемент.<br>
|
||||
Материал: Монолитный поликарбонат 2мм.<br>
|
||||
Количество: 2 шт.
|
||||
</td>
|
||||
<td><a href="https://github.com/CopterExpress/clover/raw/master/docs/assets/dxf/4.2/small_leg.dxf"><code>small_leg.dxf</code></a></td>
|
||||
</tr>
|
||||
</table>
|
||||
|
||||
## Клевер 4
|
||||
|
||||
### 3D печать
|
||||
|
||||
@@ -34,6 +34,7 @@
|
||||
|Программное определение падений в PX4||
|
||||
|Начало полета в броске|[Throw Mode](https://ardupilot.org/copter/docs/throw-mode.html) в ArduPilot.|
|
||||
|Полет коптера на точку на изображении с камеры, направленной вертикально вниз||
|
||||
|Внедрение лидара ([RPLIDAR](https://www.slamtec.com/en/Lidar)) в Клевер||
|
||||
|Зарядная станция для коптера на солнечном концентраторе|<!-- placeholder for gitbook-->|
|
||||
|
||||
Вышеперечисленные и другие проекты вы также можете реализовать в рамках конкурса проектов [Copter Hack](https://ru.coex.tech/copterhack). Мы приглашаем команды для реализации проектов и в других форматах.
|
||||
|
||||