当前位置:   article > 正文

PX4实战之旅(三):通过OFFBOARD模式控制无人机自主飞行_px4飞offboard模式

px4飞offboard模式

前言

固件:PX4 1.13.1

一、添加自定义模块

PX4-Autopilot/src/modules目录下新建control_node文件夹
在这里插入图片描述
control_node文件夹下新建下面四个文件
在这里插入图片描述
新建CMakeLists.txt,复制下面内容进去:

px4_add_module(
	MODULE modules__control_node
	MAIN control_node
	SRCS
		control_node.cpp
	)
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6

新建Kconfig,复制下面内容进去:

menuconfig MODULES_CONTROL_NODE
	bool "control_node"
	default n
	---help---
		Enable support for control_node
  • 1
  • 2
  • 3
  • 4
  • 5

新建control_node.cpp,复制下面内容进去:

#include "control_node.h"

#include <px4_platform_common/getopt.h>
#include <px4_platform_common/log.h>
#include <px4_platform_common/posix.h>

#include <uORB/topics/parameter_update.h>


int ControlNode::print_status()
{
    PX4_INFO("Running");
    // TODO: print additional runtime information about the state of the module

    return 0;
}

int ControlNode::custom_command(int argc, char *argv[])
{
    /*
    if (!is_running()) {
        print_usage("not running");
        return 1;
    }

    // additional custom commands can be handled like this:
    if (!strcmp(argv[0], "do-something")) {
        get_instance()->do_something();
        return 0;
    }
     */

    return print_usage("unknown command");
}


int ControlNode::task_spawn(int argc, char *argv[])
{
    _task_id = px4_task_spawn_cmd("module",
                                  SCHED_DEFAULT,
                                  SCHED_PRIORITY_DEFAULT,
                                  1024,
                                  (px4_main_t)&run_trampoline,
                                  (char *const *)argv);

    if (_task_id < 0)
    {
        _task_id = -1;
        return -errno;
    }

    return 0;
}

ControlNode *ControlNode::instantiate(int argc, char *argv[])
{
    int example_param = 0;
    bool example_flag = false;
    bool error_flag = false;

    int myoptind = 1;
    int ch;
    const char *myoptarg = nullptr;

    // parse CLI arguments
    while ((ch = px4_getopt(argc, argv, "p:f", &myoptind, &myoptarg)) != EOF)
    {
        switch (ch)
        {
            case 'p':
                example_param = (int)strtol(myoptarg, nullptr, 10);
                break;

            case 'f':
                example_flag = true;
                break;

            case '?':
                error_flag = true;
                break;

            default:
                PX4_WARN("unrecognized flag");
                error_flag = true;
                break;
        }
    }

    if (error_flag)
    {
        return nullptr;
    }

    ControlNode *instance = new ControlNode(example_param, example_flag);

    if (instance == nullptr)
    {
        PX4_ERR("alloc failed");
    }

    return instance;
}

ControlNode::ControlNode(int example_param, bool example_flag)
    : ModuleParams(nullptr)
{
}

void ControlNode::run()
{
    //记录起始点位置
    float begin_x;
    float begin_y;
    float begin_z;

    float_t xy_rad=1;
    float_t z_rad=1;
    float_t yaw_rad=0.1;
//进入offboard模式并解锁
    while(!should_exit())
    {
        _vehicle_status_sub.copy(&_status);
        if((_status.nav_state==vehicle_status_s::NAVIGATION_STATE_OFFBOARD)&&(_status.arming_state==vehicle_status_s::ARMING_STATE_ARMED))
        {
            PX4_INFO("in offboard and armed");
            break;
        }
        _command.target_system = _status.system_id;
        _command.target_component = _status.component_id;
        ocm.timestamp = hrt_absolute_time();
        _vehicle_local_position_sub.copy(&_vehicle_local_position);
        sp_local.x=_vehicle_local_position.x;
        sp_local.y=_vehicle_local_position.y;
        sp_local.z=_vehicle_local_position.z-5;
        sp_local.timestamp = hrt_absolute_time();
        _trajectory_setpoint_pub.publish(sp_local);
        ocm.position=true;
        ocm.timestamp = hrt_absolute_time();
        _offboard_control_mode_pub.publish(ocm);
        _command.command =vehicle_command_s::VEHICLE_CMD_DO_SET_MODE;
        _command.param1=1.0f;
        _command.param2=PX4_CUSTOM_MAIN_MODE_OFFBOARD;
        _command.timestamp = hrt_absolute_time();
        _vehicle_command_pub.publish(_command);
        usleep(10000);
        _command.command = vehicle_command_s::VEHICLE_CMD_COMPONENT_ARM_DISARM;
        _command.param1 = 1.0f;
        _command.timestamp = hrt_absolute_time();
        _vehicle_command_pub.publish(_command);
    }
//记录当前点的位置
    _vehicle_local_position_sub.copy(&_vehicle_local_position);
    begin_x=_vehicle_local_position.x;
    begin_y=_vehicle_local_position.y;
    begin_z=_vehicle_local_position.z;
    time_tick=hrt_absolute_time();
    //业务逻辑
    while (!should_exit())
    {
        _vehicle_local_position_sub.copy(&_vehicle_local_position);
        if(flag==0)//升至5米
        {
            flag++;
            memset(&sp_local,0,sizeof(vehicle_local_position_setpoint_s));
            sp_local.x=begin_x;
            sp_local.y=begin_y;
            sp_local.z=begin_z-5;
                    ocm.position=true;
                    ocm.velocity=false;
                    ocm.acceleration=false;
            PX4_INFO("pos 005");
        }
        if((flag==1)&&(abs(_vehicle_local_position.x-sp_local.x)<xy_rad)&&(abs(_vehicle_local_position.y-sp_local.y)<xy_rad)&&(abs(_vehicle_local_position.z-sp_local.z)<z_rad))//升至5米
        {
            if(flag2==0)
            {
                flag2++;
                time_tick=hrt_absolute_time();
            }
            if((flag2==1)&&(hrt_absolute_time()-time_tick)>1000000)
            {
                flag++;
                memset(&sp_local,0,sizeof(vehicle_local_position_setpoint_s));
                sp_local.x=begin_x+5;
                sp_local.y=begin_y;
                sp_local.z=begin_z-5;
                sp_local.vx=(float)NAN;
                sp_local.vy=(float)NAN;
                sp_local.vz=(float)NAN;
                sp_local.acceleration[0]=(float)NAN;
                sp_local.acceleration[1]=(float)NAN;
                sp_local.acceleration[2]=(float)NAN;
                ocm.position=true;
                ocm.velocity=false;
                ocm.acceleration=false;
                time_tick=hrt_absolute_time();
                PX4_INFO("pos 505");
            }

        }
        if((flag==2)&&(abs(_vehicle_local_position.x-sp_local.x)<xy_rad)&&(abs(_vehicle_local_position.y-sp_local.y)<xy_rad)&&(abs(_vehicle_local_position.z-sp_local.z)<z_rad))//升至5米
        {
            if(flag2==1)
            {
                flag2++;
                time_tick=hrt_absolute_time();
            }
            if((flag2==2)&&(hrt_absolute_time()-time_tick)>1000000)
            {
                flag++;
                memset(&sp_local,0,sizeof(vehicle_local_position_setpoint_s));
                sp_local.x=begin_x+5;
                sp_local.y=begin_y+5;
                sp_local.z=begin_z-5;
                sp_local.vx=(float)NAN;
                sp_local.vy=(float)NAN;
                sp_local.vz=(float)NAN;
                sp_local.acceleration[0]=(float)NAN;
                sp_local.acceleration[1]=(float)NAN;
                sp_local.acceleration[2]=(float)NAN;
                        ocm.position=true;
                        ocm.velocity=false;
                        ocm.acceleration=false;
                time_tick=hrt_absolute_time();
                PX4_INFO("pos 555");
            }

        }
        if(flag==3&&(abs(_vehicle_local_position.x-sp_local.x)<xy_rad)&&(abs(_vehicle_local_position.y-sp_local.y)<xy_rad)&&(abs(_vehicle_local_position.z-sp_local.z)<z_rad))
        {
            if(flag2==2)
            {
                flag2++;
                time_tick=hrt_absolute_time();
            }
            if((flag2==3)&&(hrt_absolute_time()-time_tick)>1000000)
            {
            flag++;
            memset(&sp_local,0,sizeof(vehicle_local_position_setpoint_s));
            sp_local.x=begin_x+5;
            sp_local.y=begin_y+5;
            sp_local.z=begin_z-5;
            sp_local.vx=(float)NAN;
            sp_local.vy=(float)NAN;
            sp_local.vz=(float)NAN;
            sp_local.acceleration[0]=(float)NAN;
            sp_local.acceleration[1]=(float)NAN;
            sp_local.acceleration[2]=(float)NAN;
            sp_local.yaw=1;
            sp_local.yawspeed=(float)NAN;
            ocm.position=true;
            ocm.velocity=false;
            ocm.acceleration=false;
            PX4_INFO("yaw");
            }
        }
        if(flag==4&&(abs(_vehicle_local_position.heading-sp_local.yaw)<yaw_rad))
        {
            if(flag2==3)
            {
                flag2++;
                time_tick=hrt_absolute_time();
            }
            if((flag2==4)&&(hrt_absolute_time()-time_tick)>1000000)
            {
            flag++;
            memset(&sp_local,0,sizeof(vehicle_local_position_setpoint_s));
            sp_local.x=begin_x+5;
            sp_local.y=begin_y+5;
            sp_local.z=begin_z-5;
            sp_local.vx=(float)NAN;
            sp_local.vy=(float)NAN;
            sp_local.vz=(float)NAN;
            sp_local.acceleration[0]=(float)NAN;
            sp_local.acceleration[1]=(float)NAN;
            sp_local.acceleration[2]=(float)NAN;
            sp_local.yaw=(float)NAN;
            sp_local.yawspeed=1;
            ocm.position=true;
            ocm.velocity=false;
            ocm.acceleration=false;
            PX4_INFO("yawspeed");
            }
        }
        if(flag==5)
        {
            if(flag2==4)
            {
                flag2++;
                time_tick=hrt_absolute_time();
            }
            if((flag2==5)&&(hrt_absolute_time()-time_tick)>5000000)
            {
            flag++;
            memset(&sp_local,0,sizeof(vehicle_local_position_setpoint_s));
            sp_local.x=(float)NAN;
            sp_local.y=(float)NAN;
            sp_local.z=begin_z-5;
            sp_local.vx=1;
            sp_local.vy=0;
            sp_local.vz=(float)NAN;
            sp_local.acceleration[0]=(float)NAN;
            sp_local.acceleration[1]=(float)NAN;
            sp_local.acceleration[2]=(float)NAN;
            sp_local.yaw=(float)NAN;
            sp_local.yawspeed=(float)NAN;
            ocm.position=true;
            ocm.velocity=true;
            ocm.acceleration=false;
            PX4_INFO("velocity");
            }
        }
        if(flag==6)
        {
            if(flag2==5)
            {
                flag2++;
                time_tick=hrt_absolute_time();
            }
            if((flag2==6)&&(hrt_absolute_time()-time_tick)>5000000)
            {
            flag++;
            memset(&sp_local,0,sizeof(vehicle_local_position_setpoint_s));
            sp_local.x=(float)NAN;
            sp_local.y=(float)NAN;
            sp_local.z=begin_z-5;
            sp_local.vx=(float)NAN;
            sp_local.vy=(float)NAN;
            sp_local.vz=(float)NAN;
            sp_local.acceleration[0]=0;
            sp_local.acceleration[1]=1;
            sp_local.acceleration[2]=(float)NAN;
            sp_local.yaw=(float)NAN;
            sp_local.yawspeed=(float)NAN;
            ocm.position=true;
            ocm.velocity=false;
            ocm.acceleration=true;
            PX4_INFO("acceleration");
            }
        }

        if(flag==7)
        {
            if(flag2==6)
            {
                flag2++;
                time_tick=hrt_absolute_time();
            }
            if((flag2==7)&&(hrt_absolute_time()-time_tick)>5000000)
            {
            flag++;
            _command.command =vehicle_command_s::VEHICLE_CMD_DO_SET_MODE;
            _command.param1=1.0f;
            _command.param2=PX4_CUSTOM_MAIN_MODE_AUTO;
            _command.param3=PX4_CUSTOM_SUB_MODE_AUTO_RTL;
            _command.timestamp = hrt_absolute_time();
            _vehicle_command_pub.publish(_command);
            PX4_INFO("return");
            }
        }


if(ocm.position||ocm.velocity||ocm.acceleration)
{
        ocm.timestamp = hrt_absolute_time();
        _offboard_control_mode_pub.publish(ocm);
        _vehicle_status_sub.copy(&_status);
if(_status.nav_state==vehicle_status_s::NAVIGATION_STATE_OFFBOARD)
{
        sp_local.timestamp = hrt_absolute_time();
        _trajectory_setpoint_pub.publish(sp_local);
//        PX4_INFO("sp_local.x=%lf\n",(double)sp_local.x);
//        PX4_INFO("sp_local.y=%lf\n",(double)sp_local.y);
//        PX4_INFO("sp_local.z=%lf\n",(double)sp_local.z);
//        PX4_INFO("sp_local.vx=%lf\n",(double)sp_local.vx);
//        PX4_INFO("sp_local.vy=%lf\n",(double)sp_local.vy);
//        PX4_INFO("sp_local.vz=%lf\n",(double)sp_local.vz);
}
}
        usleep(100000);

        parameters_update();
    }
}

void ControlNode::parameters_update(bool force)
{
    // check for parameter updates
    if (_parameter_update_sub.updated() || force)
    {
        // clear update
        parameter_update_s update;
        _parameter_update_sub.copy(&update);

        // update parameters from storage
        updateParams();
    }
}

int ControlNode::print_usage(const char *reason)
{
    if (reason)
    {
        PX4_WARN("%s\n", reason);
    }

    PRINT_MODULE_DESCRIPTION(
        R"DESCR_STR(
### Description
Section that describes the provided module functionality.

This is a template for a module running as a task in the background with start/stop/status functionality.

### Implementation
Section describing the high-level implementation of this module.

### Examples
CLI usage example:
$ module start -f -p 42

)DESCR_STR");

	PRINT_MODULE_USAGE_NAME("module", "template");
	PRINT_MODULE_USAGE_COMMAND("start");
	PRINT_MODULE_USAGE_PARAM_FLAG('f', "Optional example flag", true);
	PRINT_MODULE_USAGE_PARAM_INT('p', 0, 0, 1000, "Optional example parameter", true);
	PRINT_MODULE_USAGE_DEFAULT_COMMANDS();

	return 0;
}

int control_node_main(int argc, char *argv[])
{
	return ControlNode::main(argc, argv);
}


  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35
  • 36
  • 37
  • 38
  • 39
  • 40
  • 41
  • 42
  • 43
  • 44
  • 45
  • 46
  • 47
  • 48
  • 49
  • 50
  • 51
  • 52
  • 53
  • 54
  • 55
  • 56
  • 57
  • 58
  • 59
  • 60
  • 61
  • 62
  • 63
  • 64
  • 65
  • 66
  • 67
  • 68
  • 69
  • 70
  • 71
  • 72
  • 73
  • 74
  • 75
  • 76
  • 77
  • 78
  • 79
  • 80
  • 81
  • 82
  • 83
  • 84
  • 85
  • 86
  • 87
  • 88
  • 89
  • 90
  • 91
  • 92
  • 93
  • 94
  • 95
  • 96
  • 97
  • 98
  • 99
  • 100
  • 101
  • 102
  • 103
  • 104
  • 105
  • 106
  • 107
  • 108
  • 109
  • 110
  • 111
  • 112
  • 113
  • 114
  • 115
  • 116
  • 117
  • 118
  • 119
  • 120
  • 121
  • 122
  • 123
  • 124
  • 125
  • 126
  • 127
  • 128
  • 129
  • 130
  • 131
  • 132
  • 133
  • 134
  • 135
  • 136
  • 137
  • 138
  • 139
  • 140
  • 141
  • 142
  • 143
  • 144
  • 145
  • 146
  • 147
  • 148
  • 149
  • 150
  • 151
  • 152
  • 153
  • 154
  • 155
  • 156
  • 157
  • 158
  • 159
  • 160
  • 161
  • 162
  • 163
  • 164
  • 165
  • 166
  • 167
  • 168
  • 169
  • 170
  • 171
  • 172
  • 173
  • 174
  • 175
  • 176
  • 177
  • 178
  • 179
  • 180
  • 181
  • 182
  • 183
  • 184
  • 185
  • 186
  • 187
  • 188
  • 189
  • 190
  • 191
  • 192
  • 193
  • 194
  • 195
  • 196
  • 197
  • 198
  • 199
  • 200
  • 201
  • 202
  • 203
  • 204
  • 205
  • 206
  • 207
  • 208
  • 209
  • 210
  • 211
  • 212
  • 213
  • 214
  • 215
  • 216
  • 217
  • 218
  • 219
  • 220
  • 221
  • 222
  • 223
  • 224
  • 225
  • 226
  • 227
  • 228
  • 229
  • 230
  • 231
  • 232
  • 233
  • 234
  • 235
  • 236
  • 237
  • 238
  • 239
  • 240
  • 241
  • 242
  • 243
  • 244
  • 245
  • 246
  • 247
  • 248
  • 249
  • 250
  • 251
  • 252
  • 253
  • 254
  • 255
  • 256
  • 257
  • 258
  • 259
  • 260
  • 261
  • 262
  • 263
  • 264
  • 265
  • 266
  • 267
  • 268
  • 269
  • 270
  • 271
  • 272
  • 273
  • 274
  • 275
  • 276
  • 277
  • 278
  • 279
  • 280
  • 281
  • 282
  • 283
  • 284
  • 285
  • 286
  • 287
  • 288
  • 289
  • 290
  • 291
  • 292
  • 293
  • 294
  • 295
  • 296
  • 297
  • 298
  • 299
  • 300
  • 301
  • 302
  • 303
  • 304
  • 305
  • 306
  • 307
  • 308
  • 309
  • 310
  • 311
  • 312
  • 313
  • 314
  • 315
  • 316
  • 317
  • 318
  • 319
  • 320
  • 321
  • 322
  • 323
  • 324
  • 325
  • 326
  • 327
  • 328
  • 329
  • 330
  • 331
  • 332
  • 333
  • 334
  • 335
  • 336
  • 337
  • 338
  • 339
  • 340
  • 341
  • 342
  • 343
  • 344
  • 345
  • 346
  • 347
  • 348
  • 349
  • 350
  • 351
  • 352
  • 353
  • 354
  • 355
  • 356
  • 357
  • 358
  • 359
  • 360
  • 361
  • 362
  • 363
  • 364
  • 365
  • 366
  • 367
  • 368
  • 369
  • 370
  • 371
  • 372
  • 373
  • 374
  • 375
  • 376
  • 377
  • 378
  • 379
  • 380
  • 381
  • 382
  • 383
  • 384
  • 385
  • 386
  • 387
  • 388
  • 389
  • 390
  • 391
  • 392
  • 393
  • 394
  • 395
  • 396
  • 397
  • 398
  • 399
  • 400
  • 401
  • 402
  • 403
  • 404
  • 405
  • 406
  • 407
  • 408
  • 409
  • 410
  • 411
  • 412
  • 413
  • 414
  • 415
  • 416
  • 417
  • 418
  • 419
  • 420
  • 421
  • 422
  • 423
  • 424
  • 425
  • 426
  • 427
  • 428
  • 429
  • 430
  • 431
  • 432
  • 433
  • 434
  • 435
  • 436
  • 437

新建control_node.h,复制下面内容进去:

#pragma once
#include "commander/px4_custom_mode.h"
#include <px4_platform_common/module.h>
#include <px4_platform_common/module_params.h>
#include <uORB/Subscription.hpp>
#include <uORB/Publication.hpp>
#include <uORB/SubscriptionInterval.hpp>
#include <uORB/topics/parameter_update.h>
#include <uORB/topics/vehicle_local_position.h>
#include <uORB/topics/vehicle_local_position_setpoint.h>
#include <uORB/topics/vehicle_status.h>
#include <uORB/topics/home_position.h>
#include <uORB/topics/vehicle_command.h>
#include <uORB/topics/offboard_control_mode.h>
#include <uORB/topics/position_setpoint_triplet.h>
#include <uORB/topics/vehicle_command_ack.h>
#include <uORB/topics/vehicle_attitude_setpoint.h>

using namespace time_literals;

extern "C" __EXPORT int control_node_main(int argc, char *argv[]);


class ControlNode : public ModuleBase<ControlNode>, public ModuleParams
{
public:
	ControlNode(int example_param, bool example_flag);

	virtual ~ControlNode() = default;

	/** @see ModuleBase */
	static int task_spawn(int argc, char *argv[]);

	/** @see ModuleBase */
	static ControlNode *instantiate(int argc, char *argv[]);

	/** @see ModuleBase */
	static int custom_command(int argc, char *argv[]);

	/** @see ModuleBase */
	static int print_usage(const char *reason = nullptr);

	/** @see ModuleBase::run() */
	void run() override;

	/** @see ModuleBase::print_status() */
	int print_status() override;

private:

	/**
	 * Check for parameter changes and update them if needed.
	 * @param parameter_update_sub uorb subscription to parameter_update
	 * @param force for a parameter update
	 */
	void parameters_update(bool force = false);


	DEFINE_PARAMETERS(
		(ParamInt<px4::params::SYS_AUTOSTART>) _param_sys_autostart,   /**< example parameter */
		(ParamInt<px4::params::SYS_AUTOCONFIG>) _param_sys_autoconfig  /**< another parameter */
	)
	
    uint64_t time_tick=hrt_absolute_time();
    int flag=0,flag2=0;
    vehicle_local_position_s _vehicle_local_position;
    vehicle_status_s _status;
    vehicle_command_s _command = {};
    offboard_control_mode_s ocm{};
    position_setpoint_triplet_s _pos_sp_triplet{};
    vehicle_command_ack_s _ack{};
    vehicle_local_position_setpoint_s sp_local{};
    vehicle_attitude_setpoint_s attitude_setpoint{};
	// Subscriptions
	uORB::SubscriptionInterval _parameter_update_sub{ORB_ID(parameter_update), 1_s};
        uORB::Subscription _vehicle_local_position_sub{ORB_ID(vehicle_local_position)};
        uORB::Subscription _vehicle_status_sub{ORB_ID(vehicle_status)};
       
       // Publications
       uORB::Publication<offboard_control_mode_s>		_offboard_control_mode_pub{ORB_ID(offboard_control_mode)};
       uORB::Publication<vehicle_command_s>		_vehicle_command_pub{ORB_ID(vehicle_command)};
       uORB::Publication<position_setpoint_triplet_s>		_position_setpoint_triplet_pub{ORB_ID(position_setpoint_triplet)};
       uORB::Publication<vehicle_local_position_setpoint_s>	_trajectory_setpoint_pub{ORB_ID(trajectory_setpoint)};
};
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35
  • 36
  • 37
  • 38
  • 39
  • 40
  • 41
  • 42
  • 43
  • 44
  • 45
  • 46
  • 47
  • 48
  • 49
  • 50
  • 51
  • 52
  • 53
  • 54
  • 55
  • 56
  • 57
  • 58
  • 59
  • 60
  • 61
  • 62
  • 63
  • 64
  • 65
  • 66
  • 67
  • 68
  • 69
  • 70
  • 71
  • 72
  • 73
  • 74
  • 75
  • 76
  • 77
  • 78
  • 79
  • 80
  • 81
  • 82
  • 83
  • 84

添加到编译脚本
打开下图文件
在这里插入图片描述
添加一行

CONFIG_MODULES_CONTROL_NODE=y
  • 1

在这里插入图片描述

二、测试

执行:

make px4_sitl_default gazebo
  • 1

打开仿真后执行

control_node start
  • 1

正常的话无人机会进入Offboard,并起飞到5米高

声明:本文内容由网友自发贡献,不代表【wpsshop博客】立场,版权归原作者所有,本站不承担相应法律责任。如您发现有侵权的内容,请联系我们。转载请注明出处:https://www.wpsshop.cn/w/凡人多烦事01/article/detail/393229?site
推荐阅读
相关标签
  

闽ICP备14008679号