I am currently working on integrating the 3DM CV7 AHRS IMU with ArduCopter. This IMU provides orientation and sensor data via serial communication (UART), and I would like to interface it with ArduCopter through the existing AP_ExternalAHRS system.
I noticed that support for the MicroStrain 3DM GQ7 and 3DM CV5/GX5 IMUs is already present in the codebase under the AP_ExternalAHRS folder (specifically AP_ExternalAHRS_MicroStrain7.cpp and AP_ExternalAHRS_MicroStrain5.cpp). These classes seem to handle communication with similar IMUs, so I would like to use them as a reference for implementing the 3DM CV7 support.
My main questions are:
Do I need to create a new class for the 3DM CV7, or can I reuse existing functionality? Should I create a new class like AP_ExternalAHRS_MicroStrainCV7.cpp, or is it possible to extend the existing functionality? What would be the best approach to integrating the 3DM CV7 AHRS with ArduCopter without reinventing the wheel?
Which classes should I reference in the AP_ExternalAHRS folder? I’m considering using the AP_ExternalAHRS_MicroStrain7.cpp (for the 3DM GQ7) and AP_ExternalAHRS_MicroStrain5.cpp (for the CV5/GX5) files as templates. Are these the right files to reference, or are there other classes that I should look at to handle the 3DM CV7 integration?
What functions do I need to implement for the 3DM CV7? From my understanding, I will need to implement certain functions like build_packet(), post_imu(), and post_filter() to process the 3DM CV7 IMU data. Should I follow the pattern from the existing MicroStrain IMU classes? Additionally, will I need to implement the quaternion-to-Euler conversion, similar to how it’s done in the code below?
void AP_ExternalAHRS_MicroStrainCV7::get_orientation(float &roll, float &pitch, float &yaw) const {
if (!state.have_quaternion) {
roll = pitch = yaw = 0.0f;
return;
}
const float w = state.quat.w;
const float x = state.quat.x;
const float y = state.quat.y;
const float z = state.quat.z;
roll = std::atan2(2.0f * (w * x + y * z), 1.0f - 2.0f * (x * x + y * y));
pitch = std::asin(2.0f * (w * y - z * x));
yaw = std::atan2(2.0f * (w * z + x * y), 1.0f - 2.0f * (y * y + z * z));
constexpr float rad_to_deg = 180.0f / 3.14159265359f;
roll *= rad_to_deg;
pitch *= rad_to_deg;
yaw *= rad_to_deg;
}
How to properly integrate the 3DM CV7 IMU data into ArduCopter? Once the data is processed, I need to pass it to ArduCopter’s other systems (e.g., GPS, compass, barometer, and filter). What is the best way to ensure that the 3DM CV7 data is integrated correctly, especially within the context of ArduCopter?
ArduCopter Parameters for SITL Testing:
Additionally, for the integration to work properly during Software in the Loop (SITL) testing, I plan to set the following parameters in Mission Planner:
AHRS_EKF_TYPE: Set to 11 to use the External AHRS as the primary estimator.
EAHRS_TYPE: Set to 2 to specify the External AHRS backend.
SERIALx_PROTOCOL: Set to 36 for the serial port used by the AHRS (e.g., SERIAL4_PROTOCOL for Pixhawk4).
SERIALx_BAUD: Set this to the baud rate (e.g., 115200 for Plane, 921600 for Copter).
EAHRS_RATE: Set this to the rate in Hz of the fastest data from the AHRS (e.g., 50 for Plane, 500 for Copter).
GPS_TYPE: Set to 2 for Pixhawk GPS or 21 for LORD GPS.
GPS_AUTO_SWITCH: Set to 0 to prevent Ardupilot from switching between GPS systems.
Summary of My Plan:
Reference AP_ExternalAHRS_MicroStrain7.cpp and AP_ExternalAHRS_MicroStrain5.cpp to understand how to interface with serial IMUs.
Write a class AP_ExternalAHRS_MicroStrainCV7.cpp, implementing functions like build_packet(), post_imu(), and post_filter().
Implement quaternion-to-Euler conversion to extract roll, pitch, and yaw from the 3DM CV7.
Set the appropriate parameters in Mission Planner to test in SITL and integrate the 3DM CV7 with ArduCopter.
I would really appreciate any help or guidance on the best approach for integrating the 3DM CV7 AHRS IMU with ArduCopter. If anyone has already worked with similar IMUs or has suggestions on how to proceed, I’d love to hear your thoughts.
No, you can use AP_ExternalAHRS_Microstrain7 as it uses many of the same packets, it will just expose slightly different data to the EKF.
That is the correct file, however you will also need to write a simulator. See SIM_MicroStrain7.cpp which can be modified to just send the CV7 data instead of all the GQ7 data.
Yea, you can re-use those existing functions, except you will have to modify post_filter to not publish the GPS data if there is no GPS.
Yes, you will need to convert orientation frames if they don’t align. You can’t use the STL by the way.
4) By using external AHRS and using post_imu.
Overall, your plan looks solid. Do you have access to a CV7 already?
Yes, I have access to the hardware. So far, I have successfully mapped the USB port using the USB-to-TTL in the SITL, and the command is running successfully.
Regarding the simulation, there are no simulation classes for testing in SITL for ArduCopter. The IMU classes are written for ArduPlane in the tools/autotest directory. Therefore, I am currently using the plane commands for running the simulation in SITL.
Your response is valuable, especially since there is no direct support for this new IMU. However, I have referred to the existing classes that are available. Currently, I’m encountering errors, such as: AHRS: invalid backend. This issue is likely related to the eahrs_type parameter, which defaults to 2 for MicroStrain5, 7 for MicroStrain7, and 11 for the newly added MicroStrainCV7.
I have attached the link to the Google Sheet where I have documented all the details related to this task. Could you please take a few minutes to review all the pages in the sheet?
Make sense. By the way, I’m not sure you need a backend. Microstrain7 (for EAHRS_TYPE) was designed to work with both the GQ7 and upcoming CV7. See if you can find a way to detect which device is connected on bootup. There’s a few packets that could work - I think this one is the closest: https://files.microstrain.com/GQ7+User+Manual/external_content/dcp/Commands/0x01/data/0x03.htm
Based on the response, you can detect whether it’s a CV7 or GQ7 using the same class, which would be handy. There’s precendence for a single EAHRS class supporting multiple products - go check out the vectornav driver as an example.
I don’t yet have time to dig into your google sheet but can dive deeper after the new year.
First of all, I want to wish you a very Happy New Year! I hope you’re doing well, and thank you for all the valuable insights you’ve shared so far. I really appreciate the time and effort you’ve invested in helping me with the integration of the 3DM CV7 IMU.
I have a few follow-up questions regarding the points you mentioned, and I would be grateful for any further guidance:
Backend Classes for CV7 in libraries/ap_externalahrs:
Do I need to write separate backend classes specifically for the 3DM CV7 in the libraries/ap_externalahrs folder, or can I extend the existing MicroStrain7 backend to support both the GQ7 and CV7 models?
I was wondering whether it’s possible to dynamically detect whether a CV7 or GQ7 is connected and adjust the behavior accordingly, as you suggested. Do you think this is the way forward, or is a new backend class required for the CV7?
Setting the eahrs_type Parameter:
Should I set the eahrs_type parameter to 7 (MicroStrain7) for the 3DM CV7, or is there a different value that I need to assign? Based on your comment, I’m not sure whether the backend class needs to distinguish the CV7 from the GQ7 using a separate type.
Modifying the sim_microstrain7.cpp File for SITL:
Since sim_microstrain7.cpp is primarily responsible for simulating GNSS data in the SITL environment and the 3DM CV7 doesn’t include GNSS data, what changes should I make to ensure that it simulates only the AHRS data and not the GNSS-related functions?
I want to ensure that I don’t end up implementing unnecessary GNSS code in the simulator for the CV7.
SITL Simulation parameters:
Could you confirm if the following SITL parameters are correct for testing the integration with the CV7 IMU in ArduCopter?
AHRS_EKF_TYPE: Set to 11 (External AHRS as the primary estimator).
EAHRS_TYPE: Set to 7 (MicroStrain7 for the CV7).
SERIALx_PROTOCOL: Set to 36 (Protocol for the AHRS IMU).
SERIALx_BAUD: Set to the baud rate (e.g., 115200 for Plane or 921600 for Copter).
EAHRS_RATE: Set to the update rate of the IMU data (e.g., 500 for Copter).
GPS_TYPE: Set to 2 for Pixhawk GPS or 21 for LORD GPS (though I understand this might not be relevant for the CV7 as it won’t be used for GNSS).
GPS_AUTO_SWITCH: Set to 0 to prevent switching between GPS systems.
SITL Commands :
I have attached an image of all the commands that i have used for simulation alongside the commands already written for simulation of the 3dm gq7 imu please refer that as well.
No, my idea is to use the same backend for all 7-series devices. Yes, as I mentioned above, with Get device information (0x01,0x03)
If there is one backend for both, you would leave the parameter as 7
Perhaps we need to add a SIM_ param. Other dev team members may have a recommendation. I’ll ask in the simulation discord thread.
Looks right, but I’m not sure where you got EAHRS_RATE from, that’s not part of the docs: External AHRS Systems — Copter documentation. Note - it’s now GPS1_TYPE and you would set that to whatever GPS hardware you still have connected.
I requested a recommendation for 3 on how to add simulator support, and Peter recommended the following in priority order.
approch 1) In SIM_Microstrain.h, make MicroStrain7 a common base, class, for both 7-series devices, then derive MicrostrainGQ7 and MicrostrainCV7 from the base for any specifics. This can allow you to re-use code, and pull out common functionality into helpers in MicroStrain7. You will then run it with -A --serial3=sim:MicroStrainGQ7 or -A --serial3=sim:MicroStrainCV7
approach 2) In SIM_Microstrain.h, create a constructor for MicroStrain7 and add a single connstructor argument to the simulator for the type that can be passed in from the CLI when you start it.
approach 3) Add a parameter like SIM_EAHRS_M7_TYPE that you set to 0 for GQ7 and 1 for CV7
Thank you so much for your valuable help in this matter. Your insights have been incredibly helpful in shaping the approach for integrating the 3DM CV7 AHRS IMU with ArduCopter. I especially appreciate the prioritization of approaches for the simulation class and the detailed guidance on handling detection logic within the existing MicroStrain7 backend.
Please extend my thanks to Peter as well for his suggestions on structuring the simulator and leveraging a common base class for the 7-series devices. The collaboration has provided much-needed clarity on how to proceed efficiently.
Currently, I am working on writing the detection logic within the existing MicroStrain7 class in the libraries/AP_ExternalAHRS directory to differentiate between the GQ7 and CV7 IMUs. I have also removed the new backend classes I initially created for CV7, as per your suggestion to use a single backend for both devices. You can refer to the removed classes in the Excel sheet I shared earlier.
If I encounter any issues or doubts while implementing the backend logic, I’ll reach out for further assistance. Thanks again for your time and support in this integration process!
Thank you ryan,
i) I’ve gone through the reference manual for the 3DM CV7, and you’re absolutely correct—the commands are exactly similar to those for the 3DM GQ7. This greatly simplifies the integration process and aligns with the approach of using the same backend for both devices.
ii) I will set the parameter as 7 for both IMUs, consistent with the shared backend design.
iii) I’ll proceed with Peter’s recommendation to make MicroStrain7 a common base class for both devices and derive MicroStrainGQ7 and MicroStrainCV7 for any specific functionality. This approach seems efficient for reusing code while accommodating any future requirements.
iv) The EAHRS_RATE parameter reference came from the documentation I have attached below. It might have been inferred or an older reference, but I’ll make the necessary adjustments based on the updated GPS1_TYPE parameter for connected GPS hardware.
Thanks. If you can separate out any functionality, such as detection of model number, into smaller separate PR’s, that will make it a lot easier for us to test, review, and merge the capabilities. When possible, small PR’s are preferred over large changes, and the team can provide you better feedback as you go.
As you suggested, I derived the MicrostrainCV7 class from the existing Microstrain7 simulation class in SIM_Microstrain.h. I have also created a new class SIM_MicrostrainCV7.cpp for the simulation of cv7 imu.
I’ll attach the classes where I have made changes below. I have also updated the AP_ExternalAHRS_MicroStrain7 header and backend class files to integrate the CV7 data by identifying the model number.
However, I am encountering the following errors:
AP: PreArm: Baro: not healthy
AP: PreArm: AHRS: MicroStrain7 ExternalAHRS: not initialised
AP: PreArm: GPS 1: Bad fix
Parameters Set for This Task:
AHRS_EKF_TYPE: 11
EAHRS_TYPE: 7 (using the existing Microstrain7 backend)
SERIAL3_PROTOCOL: 36
SERIAL3_BAUD: 115200
EAHRS_RATE: 50 Hz
EK2_GPS_TYPE: 0
GPS_AUTO_SWITCH: 1
LOG_DISARMED: 1
LOG_REPLAY: 1
INS_USE: 0
INS_USE2: 0
INS_USE3: 0
GPS1_TYPE: 21
GPS2_TYPE: 21
Simulation Command:
sim_vehicle.py -v Plane -A "--serial3=uart:/dev/3dm-cv7" --console -DG
Everything related to this task is mentioned in the Excel sheet I attached earlier; I am attaching it again.
Can you explain the possible reasons behind these errors?
Please consider using git to share your code. Trying to reproduce your results through source code sent over ArduPilot Discuss is not an effective use of time. There are more changes than what you shared to get it to compile and reproduce your steps.
All you need to do is fork the repo, push your changes to a branch, and share the branch here. No need to make a pull request until we’re ready to review something.
Good evening ryan,
As you suggested, I have gone through the documentation you shared and followed every step as mentioned. I have successfully created a fork of the ArduPilot repository and pushed my changes there. You can find the fork and my branch with the changes at the link below:
With these changes and my approach, I am still encountering the errors mentioned above in this thread in my previous message when running them in SITL. I would greatly appreciate your guidance on resolving these issues.