How to use MAV_CMD_DO_SET_ACTUATOR in MATLAB?

Settings

Pixhawk 4 (I/O PWM OUT is used, FMU PWM OUT is not used)
PX4 1.14.0
QGC 4.3.0
MATLAB R2023b

Question

I want to send rotor commands to Pixhawk from MATLAB through telemetry radio. After some search, I think MAV_CMD_DO_SET_ACTUATOR is the appropriate interface. I can arm Pixhawk from MATLAB using MAV_CMD_COMPONENT_ARM_DISARM. However, I cannot make MAV_CMD_DO_SET_ACTUATOR work. My code is as follows.

tele_com_port = "COM16";
device = serial(tele_com_port, "BaudRate", 57600);

dialect = mavlinkdialect("common.xml");
mavlink = mavlinkio(dialect);

% Arm, MAV_CMD_COMPONENT_ARM_DISARM 
cmd_arm = createcmd(dialect, "long", 400);
cmd_arm.Payload.target_system = uint8(1);
cmd_arm.Payload.param1 = single(1);
buffer_cmd_arm = serializemsg(mavlink, cmd_arm);

% Set rotor input, MAV_CMD_DO_SET_ACTUATOR
cmd_set_actuator = createcmd(dialect, "long", 187);
cmd_set_actuator.Payload.target_system = uint8(1);
cmd_set_actuator.Payload.param1 = single(0.1);
cmd_set_actuator.Payload.param2 = single(0.1);
cmd_set_actuator.Payload.param3 = single(0.1);
cmd_set_actuator.Payload.param4 = single(0.1);
buffer_cmd_set_actuator = serializemsg(mavlink, cmd_set_actuator);

fclose(device);
fopen(device);

% Arm.
fwrite(device, buffer_cmd_arm, "uint8");
fprintf("Armed\n");
% Set rotor inputs.
for i = 0: 1000
    thr = (0.8 - 0.2) / 1000 * i + 0.2; 
    cmd_set_actuator.Payload.param1 = single(thr);
    cmd_set_actuator.Payload.param2 = single(thr);
    cmd_set_actuator.Payload.param3 = single(thr);
    cmd_set_actuator.Payload.param4 = single(thr);
    buffer_cmd_set_actuator = serializemsg(mavlink, cmd_set_actuator);
    % fwrite(device, buffer_cmd_set_actuator, "uint8");
    fwrite(device, buffer_cmd_set_actuator);
    pause(0.02);
end
fprintf("Done\n");
fclose(device);

Following https://docs.px4.io/main/en/config/actuators.html, I set the rotors as shown in https://github.com/PX4/PX4-user_guide/issues/3028 (sorry but I have not found a way to upload images here.

I can arm Pixhawk. In the code above, I set the rotor inputs to increase linearly. But the rotors’ speed seem does not change. And Pixhawk disarms even when the program above is still running. So I think the rotor commands are not sent to Pixhawk correctly.

Thanks in advance.

In QGC console, using listener vehicle_command, it shows the following messages:

TOPIC: vehicle_command instance 0 #588
 vehicle_command
    timestamp: 1221441106 (0.092217 seconds ago)
    param5: 0.000000
    param6: 0.000000
    param1: 0.79940
    param2: 0.79940
    param3: 0.79940
    param4: 0.79940
    param7: -0.50000
    command: 187
    target_system: 1
    target_component: 0
    source_system: 255
    source_component: 1
    confirmation: 0
    from_external: True


TOPIC: vehicle_command instance 0 #589
 vehicle_command
    timestamp: 1221448104 (0.104648 seconds ago)
    param5: 0.000000
    param6: 0.000000
    param1: 0.80000
    param2: 0.80000
    param3: 0.80000
    param4: 0.80000
    param7: -0.50000
    command: 187
    target_system: 1
    target_component: 0
    source_system: 255
    source_component: 1
    confirmation: 0
    from_external: True

I set the command for each rotor to increase from 0.2 to 0.8 linearly. Does this mean that Pixhawk receives rotor commands? However, the rotors still rotate with constant speed…

The code is correct. There is no problem.