Embedding pkg SatelliteToolbox in a Cpp software

Hello all,

I am wondering if anyone could help me. I am new to Julia language and it is being quiete difficult to understand how to embed julia in a cpp code.

What I am trying is to use the pkg SatelliteToolbox from julia in a satellite simulator code written in cpp in order to improve the orbit propagation module with the SGP4 propagation from the SatelliteToolbox. I do not know also if it is possible (although I guess yes after reading the docu…).

I have developed the code embeding the functions and then I have implemented a test achieving the following error:

Note that the simulator is based in the ns3 library (https://www.nsnam.org/

As I see the error, it seems a library error… however, the test implemented is exactly the same for the Kepler orbit propagation written in cpp, and it is running without errors. As I have implemented the embedding code for the SGP4 propagation, since the outputs of the functions are the same, the test should be equal.

The embedded code is the following:

  std::tuple<ECICoordinates, ECICoordinates> SGP4OrbitTrajectory::propagateOrbit(double time)
 {       
      ECICoordinates eci_position;
      ECICoordinates eci_velocity;
 
     jl_init();
     jl_eval_string("using SatelliteToolbox");
     jl_module_t* SatTool = (jl_module_t *)jl_eval_string("SatelliteToolbox");
     jl_function_t *sgp4_init = jl_get_function(SatTool, "sgp4_init");
     jl_function_t *OrbitPropagatorSGP4 = jl_get_function(SatTool, "OrbitPropagatorSGP4");
     jl_function_t *propagate = jl_get_function(SatTool, "propagate!");
     
     // Convert cpp parameters to julia
     jl_value_t *sgp4_gc = jl_eval_string("sgp4_gc_wgs84");
     jl_value_t *epoch = jl_box_float64(TimeUtils::getJDEpoch()); //Should we use input time as epoch?
     jl_value_t *meanMotion = jl_box_float64(m_angular_speed);
     jl_value_t *eccentricity = jl_box_float64(m_orbit_params.eccentricity);
     jl_value_t *inclination = jl_box_float64(m_orbit_params.inclination);
     jl_value_t *raan = jl_box_float64(m_orbit_params.raan);
     jl_value_t *argPerigee = jl_box_float64(m_orbit_params.arg_perigee);
     jl_value_t *meanAnomaly = jl_box_float64(m_init_mean_anomaly);
     jl_value_t *bStar = jl_box_float64(m_bStar);
     
     struct _jl_value_t *arguments[9] = {sgp4_gc, epoch, meanMotion, eccentricity, inclination, raan, argPerigee, meanAnomaly, bStar};
    
     struct _jl_value_t *sgp4d = jl_call(sgp4_init, arguments, 9); // Initialize the data structure of SGP4 algorithm. 
   
     struct _jl_value_t *orbp = jl_call(OrbitPropagatorSGP4, &sgp4d, 1); // Create and return the orbit propagator structure.
    
     JL_GC_PUSH2(&sgp4d, &orbp);
 
     /* In julia terminal, it should run -> jl_eval_string("r_TEME, v_TEME = propagate!(orbp, t)"); 
        Then, propagate! funtion returns a 2D array object y = [r_TEME(x, y, z), v_TEME(x, y, z)].   
      */
 
     jl_array_t *y = (jl_array_t*)jl_call2(propagate, orbp, t); // Create and return the orbit propagator structure.
     double *RVTeme = (double*)jl_array_data(y);
     eci_position = RVTeme[0];
     eci_velocity = RVTeme[1];
 
     JL_GC_POP();
     jl_atexit_hook(0);
     
     return std::make_tuple(eci_position, eci_velocity);
 }

I not an expert programing… So I guess that I will have many incoherences. And the test is the following:


#ifndef __TEST_SGP4_ORBIT_HPP__
#define __TEST_SGP4_ORBIT_HPP__

#include <gtest/gtest.h>
#include <complex>

#include "dss.hpp"

#include "SGP4OrbitTrajectory.hpp"
#include "OrbitalParams.hpp"
#include "ECICoordinates.hpp"
#include "TLE.hpp"
#include "SimulatorError.hpp"

namespace
{
    class SGP4OrbitTest : public ::testing::Test
    {
    protected:
        std::string tle_line;
        TLE* random_tle;
        SGP4OrbitTrajectory* orbit;

        std::vector<std::tuple<ECICoordinates, ECICoordinates>> current_state;
        std::vector<ECICoordinates> current_position;
        std::vector<ECICoordinates> current_velocity;
        std::vector<double> time {0.0, 360.0, 720.0, 1080.0, 1440.0, 1800.0, 2160.0, 2520.0,
                                  2880.0, 3240.0, 3600.0, 3960.0, 4320.0 };

        ECICoordinates p;
        ECICoordinates p1;
        ECICoordinates p2;
        ECICoordinates p3;
        ECICoordinates p4;
        ECICoordinates p5;
        ECICoordinates p6;
        ECICoordinates p7;
        ECICoordinates p8;
        ECICoordinates p9;
        ECICoordinates p1o;
        ECICoordinates p11;
        ECICoordinates p12;

        ECICoordinates v;
        ECICoordinates v1;
        ECICoordinates v2;
        ECICoordinates v3;
        ECICoordinates v4;
        ECICoordinates v5;
        ECICoordinates v6;
        ECICoordinates v7;
        ECICoordinates v8;
        ECICoordinates v9;
        ECICoordinates v1o;
        ECICoordinates v11;
        ECICoordinates v12;

        virtual void SetUp()
        {
            for(int k = 0; k < 13; k++) {
                current_state.push_back(std::make_tuple(ECICoordinates(0.0, 0.0, 0.0), ECICoordinates(0.0, 0.0, 0.0)));
                current_position.push_back(ECICoordinates(0.0, 0.0, 0.0));
                current_velocity.push_back(ECICoordinates(0.0, 0.0, 0.0));
            }
            /* Random Satellite TLE */
            tle_line = "RANDOM 1\n";
            tle_line += "1 00005U 58002B   00179.78495062  .00000023  00000-0  28098-4 0  4753\n";
            tle_line += "2 00005  34.2682 348.7242 1859667 331.7664  19.3264 10.82419157413667";
            random_tle = new TLE(tle_line);
   
            /* Expected results */

            p = ECICoordinates(7022.46529266, -1400.08296755, 0.03995155);
            p1 = ECICoordinates(-7154.03120202, -3783.17682504, -3536.19412294);
            p2 = ECICoordinates(-7134.59340119, 6531.68641334, 3260.27186483);
            p3 = ECICoordinates(5568.53901181, 4492.06992591, 3863.87641983);
            p4 = ECICoordinates(-938.55923943, -6268.18748831, -4294.02924751);
            p5 = ECICoordinates(-9680.56121728, 2802.47771354, 124.10688038);
            p6 = ECICoordinates(190.19796988, 7746.96653614, 5110.00675412);
            p7 = ECICoordinates(5579.55640116, -3995.61396789, -1518.82108966);
            p8 = ECICoordinates(-8650.73082219, -1914.93811525, -3007.03603443);
            p9 = ECICoordinates(-5429.79204164, 7574.36493792, 3747.39305236);
            p1o = ECICoordinates(6759.04583722, 2001.58198220, 2783.55192533);
            p11 = ECICoordinates(-3791.44531559, -5712.95617894, -4533.48630714);
            p12 = ECICoordinates(-9060.47373569, 4658.70952502, 813.68673153);

            v = ECICoordinates(1.893841015, 6.405893759, 4.534807250);
            v1 = ECICoordinates(4.741887409, -4.151817765, -2.093935425 );
            v2 = ECICoordinates(-4.113793027, -2.911922039, -2.557327851);
            v3 = ECICoordinates(-4.209106476, 5.159719888, 2.744852980);
            v4 = ECICoordinates(7.536105209, -0.427127707, 0.989878080);
            v5 = ECICoordinates(-0.905874102, -4.659467970, -3.227347517);
            v6 = ECICoordinates(-6.112325142, 1.527008184, -0.139152358);
            v7 = ECICoordinates(4.767927483, 5.123185301, 4.276837355);
            v8 = ECICoordinates(3.067165127, -4.828384068, -2.515322836);
            v9 = ECICoordinates(-4.999442110, -1.800561422, -2.229392830);
            v1o = ECICoordinates(-2.180993947, 6.402085603, 3.644723952);
            v11 = ECICoordinates(6.668817493, -2.516382327, -0.082384354);
            v12 = ECICoordinates(-2.232832783, -4.110453490, -3.157345433);          

        }

    };


    TEST_F(SGP4OrbitTest, testSGP4Propagation)
    {
        double error = std::pow(10, -9);
        SGP4OrbitTrajectory* random_orbit = new SGP4OrbitTrajectory(*random_tle, "random");
        random_orbit->Initialize();
        for (int i = 0; i <= 13; i++) {
            current_state[i] = random_orbit-> propagateOrbit(time[i]);
            current_position[i] = std::get<0>(current_state[i]);
            current_velocity[i] = std::get<1>(current_state[i]);
        }
        //TODO: compare y and z components.
        ASSERT_NEAR(current_position[0].x, p.x, error);
        ASSERT_NEAR(current_velocity[0].x, v.x, error);

        ASSERT_NEAR(current_position[1].x, p1.x, error);
        ASSERT_NEAR(current_velocity[1].x, v1.x, error);

        ASSERT_NEAR(current_position[2].x, p2.x, error);
        ASSERT_NEAR(current_velocity[2].x, v2.x, error);

        ASSERT_NEAR(current_position[3].x, p3.x, error);
        ASSERT_NEAR(current_velocity[3].x, v3.x, error);

        ASSERT_NEAR(current_position[4].x, p4.x, error);
        ASSERT_NEAR(current_velocity[4].x, v4.x, error);

        ASSERT_NEAR(current_position[5].x, p5.x, error);
        ASSERT_NEAR(current_velocity[5].x, v5.x, error);

        ASSERT_NEAR(current_position[6].x, p6.x, error);
        ASSERT_NEAR(current_velocity[6].x, v6.x, error);    

        ASSERT_NEAR(current_position[7].x, p7.x, error);
        ASSERT_NEAR(current_velocity[7].x, v7.x, error);   

        ASSERT_NEAR(current_position[8].x, p8.x, error);
        ASSERT_NEAR(current_velocity[8].x, v8.x, error); 

        ASSERT_NEAR(current_position[9].x, p9.x, error);
        ASSERT_NEAR(current_velocity[9].x, v9.x, error);

        ASSERT_NEAR(current_position[10].x, p1o.x, error);
        ASSERT_NEAR(current_velocity[10].x, v1o.x, error);

        ASSERT_NEAR(current_position[11].x, p11.x, error);
        ASSERT_NEAR(current_velocity[11].x, v11.x, error);

        ASSERT_NEAR(current_position[12].y, p12.y, error);
        ASSERT_NEAR(current_velocity[12].y, v12.y, error);   
    }
}

#endif /* __TEST_SGP4_ORBIT_HPP__ */

And the cmake code to find the julia library is

# -- Julia library:
find_package(Julia REQUIRED)
include_directories(SYSTEM ${Julia_INCLUDE_DIRS})
include_directories(${JULIA_HEADER_DIR} ${JULIA_HEADER_DIR}/support ${JULIA_PATH}/usr/include )
# set the path to the library folder
link_directories(${JULIA_LIB_DIR})
# link the libraries to the executable
link_libraries (julia)
add_definitions(-DJULIA_INIT_DIR="${JULIA_LIB_DIR}")
add_definitions(-DJULIA_LOG_ENABLE)
add_definitions(-DJULIA_INIT_DIR="${JULIA_LIB_DIR}")

If anyone could help me I would appreciate it so much… I’ve been stuck a long time with that error and I have exhausted my ideas… If I have to provide more info or provide the complete files, I won’t have any inconveniences.

Many thanks in advance.

Maybe give GitHub - Clemapfel/jluna: Julia <-> C++ Wrapper with Focus on Safety, Elegance, and Ease of Use a try

It would help you and us if you could reduce this down to a minimum, self contained example, that can reproduce the error.