https://docs.px4.io/main/en/advanced_config/imu_factory_calibration.html
PX4 OEM manufacturers can perform an IMU factory calibration in order to store persistent values for the accelerometer, gyroscope and magnetometer biases into persistent storage (usually EEPROM). This ensures that end users can always reset vehicle configurations and tuning to a safe state for flying.
This procedure will write the following parameters to /fs/mtd_caldata: CAL_ACC*, CAL_MAG*, CAL_GYRO*. This data will then be used when the parameters are set (or reset) to their default values.
WARNING
This feature relies on the FMU having a dedicated EEPROM chip or an accompanying IMU PCBA that has sufficient space for the data. PX4 will store the data to /fs/mtd_caldata, creating the file if necessary.
Note
These values cannot be stored in the frame configuration because they vary from device to device (the frame configuration defines the set of parameters that are applicable across all vehicles of the same type, such as the enabled sensors, autopilot rotation and PID tuning).
Performing the Factory Calibration
Set the parameter SYS_FAC_CAL_MODE to 1.
Perform all IMU calibrations: accelerometer, gyroscope and magnetometer.
Reboot the vehicle. This will write all CAL_ACC*, CAL_GYRO* and CAL_MAG* parameters into /fs/mtd_caldata.
Set the parameter SYS_FAC_CAL_MODE back to 0 (default).
Subsequent user calibrations will then take effect as usual (factory calibration data is only used for the parameter default values).
============
Here you can find information about calibration from mavlink
Accelerometer Calibration
The MAV_CMD_ACCELCAL_VEHICLE_POS 2 command says it’s “Used when doing accelerometer calibration.” That’s a bit ambiguous, but given it’s not working for you then the “when doing” likely implies the calibration has to be started with a different message, and the vehicle pos command is just for stepping through the positions during the calibration.
From the QGC source file that was linked to in the other post,
the APMSensorsComponentController.cc sets up the accelerometer calibration,
then delegates it to the vehicle (_vehicle->startCalibration()).
Looking in Vehicle.cc (where vehicle functionality is defined),
the calibration is started using the MAV_CMD_PREFLIGHT_CALIBRATION 6 command.
Compass Calibration
For the compass calibration, the definition in APMSensorsComponentController.cc 1 uses MAV_CMD_DO_CANCEL_MAG_CAL 1 to determine whether the flight computer supports onboard compass calibration.
Looking at the nearby commands in the message set comes up with the MAV_CMD_DO_START_MAG_CAL 3, which is presumably used to start magnetometer (compass) calibration (so we have something to look for).
The calibrateCompass method (from step 1) hands off logic to the _mavCommandResult 4 method in the same file,
where you can see that MAV_CMD_DO_START_MAG_CAL 3 is indeed used if onboard calibration is supported,
which from a search of MAG_CAL in the ArduPilot codebase 2
seems to be the case as of at least ArduSub 4.0 2 (probably can stop here, and just use that message).
Where onboard calibration isn’t supported, it instead uses _compassCal.startCalibration().
I wasn’t sure where that was defined, but it wasn’t in that file so
I checked the corresponding header file, which #includes APMCompassCal.h.
Looking in the corresponding source file,
APMCompassCal.cc 1 defines the function we’re after, as well as the various calculations that are used to perform a compass calibration externally.
The code there is quite convoluted, so I’m not certain how it tracks the calibration state (if it even does - it seems like it might just communicate via string/text messages).
Focusing back on the more promising approach, to confirm whether the MAG_CAL messages work I tried following the QGC approach from step 3. - sending a CANCEL_MAG_CAL command and seeing what kind of MAV_RESULT 1 the command is acknowledged with (as per the Command Protocol 1):
As an aside, the software team have suggested an alternative and potentially simpler approach to finding out this information (and its direct usage in Pymavlink) would be to look at mavproxy’s implementation instead. This file https://github.com/ArduPilot/MAVProxy/blob/master/MAVProxy/modules/mavproxy_calibration.py was the first result in a search for “calibration”