From d67981728965d0e6d26ae47eac9b4a0d772bb33a Mon Sep 17 00:00:00 2001 From: Oskar Weigl Date: Tue, 25 Sep 2018 19:51:06 -0700 Subject: [PATCH 1/7] add written hook ptr to protcol properties --- Firmware/fibre/cpp/include/fibre/protocol.hpp | 29 ++++++++++++------- 1 file changed, 18 insertions(+), 11 deletions(-) diff --git a/Firmware/fibre/cpp/include/fibre/protocol.hpp b/Firmware/fibre/cpp/include/fibre/protocol.hpp index ed174dd9..4eeb8d77 100644 --- a/Firmware/fibre/cpp/include/fibre/protocol.hpp +++ b/Firmware/fibre/cpp/include/fibre/protocol.hpp @@ -804,8 +804,8 @@ public: static constexpr const char * json_modifier = get_default_json_modifier(); static constexpr size_t endpoint_count = 1; - ProtocolProperty(const char * name, TProperty* property) - : name_(name), property_(property) + ProtocolProperty(const char * name, TProperty* property, void (*written_hook)(void)) + : name_(name), property_(property), written_hook_(written_hook) {} /* TODO: find out why the move constructor is not used when it could be @@ -887,32 +887,39 @@ public: handle(input, input_length, output); }*/ - const char * name_; + const char* name_; TProperty* property_; + void (*written_hook_)(void); }; // Non-const non-enum types template::value)> -ProtocolProperty make_protocol_property(const char * name, TProperty* property) { - return ProtocolProperty(name, property); +ProtocolProperty make_protocol_property( + const char * name, TProperty* property, void (*written_hook)(void) = nullptr) { + return ProtocolProperty(name, property, written_hook); }; // Const non-enum types template::value)> -ProtocolProperty make_protocol_ro_property(const char * name, const TProperty* property) { - return ProtocolProperty(name, property); +ProtocolProperty make_protocol_ro_property( + const char * name, TProperty* property, void (*written_hook)(void) = nullptr) { + return ProtocolProperty(name, property, written_hook); }; // Non-const enum types template::value)> -ProtocolProperty> make_protocol_property(const char * name, TProperty* property) { - return ProtocolProperty>(name, reinterpret_cast*>(property)); +ProtocolProperty> make_protocol_property( + const char * name, TProperty* property, void (*written_hook)(void) = nullptr) { + return ProtocolProperty>( + name, reinterpret_cast*>(property), written_hook); }; // Const enum types template::value)> -ProtocolProperty> make_protocol_ro_property(const char * name, const TProperty* property) { - return ProtocolProperty>(name, reinterpret_cast*>(property)); +ProtocolProperty> make_protocol_ro_property( + const char * name, TProperty* property, void (*written_hook)(void) = nullptr) { + return ProtocolProperty>( + name, reinterpret_cast*>(property), written_hook); }; From 66a717f929044af9f90bd008f169c1d16afa8df9 Mon Sep 17 00:00:00 2001 From: Oskar Weigl Date: Tue, 25 Sep 2018 20:23:03 -0700 Subject: [PATCH 2/7] add ctx, hook current controller bandwidth --- Firmware/MotorControl/motor.hpp | 11 ++++--- Firmware/fibre/cpp/include/fibre/protocol.hpp | 32 ++++++++++--------- 2 files changed, 24 insertions(+), 19 deletions(-) diff --git a/Firmware/MotorControl/motor.hpp b/Firmware/MotorControl/motor.hpp index 07820726..89ed74e2 100644 --- a/Firmware/MotorControl/motor.hpp +++ b/Firmware/MotorControl/motor.hpp @@ -211,10 +211,13 @@ public: make_protocol_property("motor_type", &config_.motor_type), make_protocol_property("current_lim", &config_.current_lim), make_protocol_property("requested_current_range", &config_.requested_current_range), - make_protocol_ro_property("current_control_bandwidth", &config_.current_control_bandwidth) - ), - make_protocol_function("set_current_control_bandwidth", *this, &Motor::set_current_control_bandwidth, - "current_control_bandwidth") + // make_protocol_ro_property("current_control_bandwidth", &config_.current_control_bandwidth) + make_protocol_property("current_control_bandwidth", &config_.current_control_bandwidth, + [](void* ctx) { static_cast(ctx)->update_current_controller_gains(); }, this) + ) + // ), + // make_protocol_function("set_current_control_bandwidth", *this, &Motor::set_current_control_bandwidth, + // "current_control_bandwidth") ); } }; diff --git a/Firmware/fibre/cpp/include/fibre/protocol.hpp b/Firmware/fibre/cpp/include/fibre/protocol.hpp index 4eeb8d77..0bbc43e7 100644 --- a/Firmware/fibre/cpp/include/fibre/protocol.hpp +++ b/Firmware/fibre/cpp/include/fibre/protocol.hpp @@ -804,8 +804,9 @@ public: static constexpr const char * json_modifier = get_default_json_modifier(); static constexpr size_t endpoint_count = 1; - ProtocolProperty(const char * name, TProperty* property, void (*written_hook)(void)) - : name_(name), property_(property), written_hook_(written_hook) + ProtocolProperty(const char * name, TProperty* property, + void (*written_hook)(void*), void* ctx) + : name_(name), property_(property), written_hook_(written_hook), ctx_(ctx) {} /* TODO: find out why the move constructor is not used when it could be @@ -889,37 +890,38 @@ public: const char* name_; TProperty* property_; - void (*written_hook_)(void); + void (*written_hook_)(void*); + void* ctx_; }; // Non-const non-enum types template::value)> -ProtocolProperty make_protocol_property( - const char * name, TProperty* property, void (*written_hook)(void) = nullptr) { - return ProtocolProperty(name, property, written_hook); +ProtocolProperty make_protocol_property(const char * name, TProperty* property, + void (*written_hook)(void*) = nullptr, void* ctx = nullptr) { + return ProtocolProperty(name, property, written_hook, ctx); }; // Const non-enum types template::value)> -ProtocolProperty make_protocol_ro_property( - const char * name, TProperty* property, void (*written_hook)(void) = nullptr) { - return ProtocolProperty(name, property, written_hook); +ProtocolProperty make_protocol_ro_property(const char * name, TProperty* property, + void (*written_hook)(void*) = nullptr, void* ctx = nullptr) { + return ProtocolProperty(name, property, written_hook, ctx); }; // Non-const enum types template::value)> -ProtocolProperty> make_protocol_property( - const char * name, TProperty* property, void (*written_hook)(void) = nullptr) { +ProtocolProperty> make_protocol_property(const char * name, TProperty* property, + void (*written_hook)(void*) = nullptr, void* ctx = nullptr) { return ProtocolProperty>( - name, reinterpret_cast*>(property), written_hook); + name, reinterpret_cast*>(property), written_hook, ctx); }; // Const enum types template::value)> -ProtocolProperty> make_protocol_ro_property( - const char * name, TProperty* property, void (*written_hook)(void) = nullptr) { +ProtocolProperty> make_protocol_ro_property(const char * name, TProperty* property, + void (*written_hook)(void*) = nullptr, void* ctx = nullptr) { return ProtocolProperty>( - name, reinterpret_cast*>(property), written_hook); + name, reinterpret_cast*>(property), written_hook, ctx); }; From a897054d345dad33633ad25b675547a989add2ee Mon Sep 17 00:00:00 2001 From: Oskar Weigl Date: Tue, 25 Sep 2018 20:50:35 -0700 Subject: [PATCH 3/7] actually call the hook lol --- Firmware/fibre/cpp/include/fibre/protocol.hpp | 3 +++ 1 file changed, 3 insertions(+) diff --git a/Firmware/fibre/cpp/include/fibre/protocol.hpp b/Firmware/fibre/cpp/include/fibre/protocol.hpp index 0bbc43e7..8b5e9c71 100644 --- a/Firmware/fibre/cpp/include/fibre/protocol.hpp +++ b/Firmware/fibre/cpp/include/fibre/protocol.hpp @@ -883,6 +883,9 @@ public: } void handle(const uint8_t* input, size_t input_length, StreamSink* output) final { default_readwrite_endpoint_handler(property_, input, input_length, output); + if (written_hook_ != nullptr) { + written_hook_(ctx_); + } } /*void handle(const uint8_t* input, size_t input_length, StreamSink* output) { handle(input, input_length, output); From 95d5c615502efdc151831b754c1d6d3dc0e1358b Mon Sep 17 00:00:00 2001 From: Oskar Weigl Date: Tue, 25 Sep 2018 21:05:35 -0700 Subject: [PATCH 4/7] only call hook when written --- Firmware/fibre/cpp/include/fibre/protocol.hpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Firmware/fibre/cpp/include/fibre/protocol.hpp b/Firmware/fibre/cpp/include/fibre/protocol.hpp index 8b5e9c71..ccf225c5 100644 --- a/Firmware/fibre/cpp/include/fibre/protocol.hpp +++ b/Firmware/fibre/cpp/include/fibre/protocol.hpp @@ -883,7 +883,7 @@ public: } void handle(const uint8_t* input, size_t input_length, StreamSink* output) final { default_readwrite_endpoint_handler(property_, input, input_length, output); - if (written_hook_ != nullptr) { + if (written_hook_ != nullptr && input_length >= sizeof(TProperty)) { written_hook_(ctx_); } } From d2e2c3a1a80733ade5c6888fdf5152408d75ae33 Mon Sep 17 00:00:00 2001 From: Oskar Weigl Date: Tue, 25 Sep 2018 21:34:16 -0700 Subject: [PATCH 5/7] use new hooks for encoder and current control bandwidth --- CHANGELOG.md | 9 +++++++++ Firmware/MotorControl/encoder.cpp | 22 ++++++++++++---------- Firmware/MotorControl/encoder.hpp | 9 ++++++--- Firmware/MotorControl/motor.cpp | 13 ++++--------- Firmware/MotorControl/motor.hpp | 6 ------ docs/hoverboard.md | 2 +- 6 files changed, 32 insertions(+), 29 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index baaf20c1..4ff031fb 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -3,6 +3,15 @@ Please add a note of your changes below this heading if you make a Pull Request. # Unreleased +### Added +* Hook to execute protocol property written callback + +### Changed +* Using new hooks to calculate: + * `motor.config.current_control_bandwidth` + * This depricates `motor.set_current_control_bandwidth()` + * `encoder.config.bandwidth` + # Releases ## [0.4.4] - 2018-09-18 ### Fixed diff --git a/Firmware/MotorControl/encoder.cpp b/Firmware/MotorControl/encoder.cpp index 5b80ed8d..13fac4bb 100644 --- a/Firmware/MotorControl/encoder.cpp +++ b/Firmware/MotorControl/encoder.cpp @@ -7,6 +7,8 @@ Encoder::Encoder(const EncoderHardwareConfig_t& hw_config, hw_config_(hw_config), config_(config) { + update_pll_gains(); + if (config.pre_calibrated && (config.mode == Encoder::MODE_HALL)) { is_ready_ = true; } @@ -241,17 +243,17 @@ static bool decode_hall(uint8_t hall_state, int32_t* hall_cnt) { } } -bool Encoder::update() { - // Calculate encoder pll gains - float pll_kp = 2.0f * config_.bandwidth; // basic conversion to discrete time - float pll_ki = 0.25f * (pll_kp * pll_kp); // Critically damped +void Encoder::update_pll_gains() { + pll_kp_ = 2.0f * config_.bandwidth; // basic conversion to discrete time + pll_ki_ = 0.25f * (pll_kp_ * pll_kp_); // Critically damped // Check that we don't get problems with discrete time approximation - if (!(current_meas_period * pll_kp < 1.0f)) { + if (!(current_meas_period * pll_kp_ < 1.0f)) { set_error(ERROR_UNSTABLE_GAIN); - return false; } +} +bool Encoder::update() { // update internal encoder state. int32_t delta_enc = 0; switch (config_.mode) { @@ -294,12 +296,12 @@ bool Encoder::update() { float delta_pos_cpr = (float)(count_in_cpr_ - (int32_t)floorf(pos_cpr_)); delta_pos_cpr = wrap_pm(delta_pos_cpr, 0.5f * (float)(config_.cpr)); // pll feedback - pos_estimate_ += current_meas_period * pll_kp * delta_pos; - pos_cpr_ += current_meas_period * pll_kp * delta_pos_cpr; + pos_estimate_ += current_meas_period * pll_kp_ * delta_pos; + pos_cpr_ += current_meas_period * pll_kp_ * delta_pos_cpr; pos_cpr_ = fmodf_pos(pos_cpr_, (float)(config_.cpr)); - vel_estimate_ += current_meas_period * pll_ki * delta_pos_cpr; + vel_estimate_ += current_meas_period * pll_ki_ * delta_pos_cpr; bool snap_to_zero_vel = false; - if (fabsf(vel_estimate_) < 0.5f * current_meas_period * pll_ki) { + if (fabsf(vel_estimate_) < 0.5f * current_meas_period * pll_ki_) { vel_estimate_ = 0.0f; //align delta-sigma on zero to prevent jitter snap_to_zero_vel = true; } diff --git a/Firmware/MotorControl/encoder.hpp b/Firmware/MotorControl/encoder.hpp index 2162d10b..6eca0536 100644 --- a/Firmware/MotorControl/encoder.hpp +++ b/Firmware/MotorControl/encoder.hpp @@ -56,6 +56,8 @@ public: bool run_offset_calibration(); bool update(); + void update_pll_gains(); + const EncoderHardwareConfig_t& hw_config_; Config_t& config_; Axis* axis_ = nullptr; // set by Axis constructor @@ -70,8 +72,8 @@ public: float pos_estimate_ = 0.0f; // [rad] float pos_cpr_ = 0.0f; // [rad] float vel_estimate_ = 0.0f; // [rad/s] - // float pll_kp_ = 0.0f; // [rad/s / rad] - // float pll_ki_ = 0.0f; // [(rad/s^2) / rad] + float pll_kp_ = 0.0f; // [rad/s / rad] + float pll_ki_ = 0.0f; // [(rad/s^2) / rad] // Updated by low_level pwm_adc_cb uint8_t hall_state_ = 0x0; // bit[0] = HallA, .., bit[2] = HallC @@ -100,7 +102,8 @@ public: make_protocol_property("cpr", &config_.cpr), make_protocol_property("offset", &config_.offset), make_protocol_property("offset_float", &config_.offset_float), - make_protocol_property("bandwidth", &config_.bandwidth), + make_protocol_property("bandwidth", &config_.bandwidth, + [](void* ctx) { static_cast(ctx)->update_pll_gains(); }, this), make_protocol_property("calib_range", &config_.calib_range) ) ); diff --git a/Firmware/MotorControl/motor.cpp b/Firmware/MotorControl/motor.cpp index 56817ee8..dc379f0c 100644 --- a/Firmware/MotorControl/motor.cpp +++ b/Firmware/MotorControl/motor.cpp @@ -6,8 +6,8 @@ Motor::Motor(const MotorHardwareConfig_t& hw_config, - const GateDriverHardwareConfig_t& gate_driver_config, - MotorConfig_t& config) : + const GateDriverHardwareConfig_t& gate_driver_config, + MotorConfig_t& config) : hw_config_(hw_config), gate_driver_config_(gate_driver_config), config_(config), @@ -17,8 +17,8 @@ Motor::Motor(const MotorHardwareConfig_t& hw_config, .EngpioNumber = gate_driver_config_.enable_pin, .nCSgpioHandle = gate_driver_config_.nCS_port, .nCSgpioNumber = gate_driver_config_.nCS_pin, - }) -{ + }) { + update_current_controller_gains(); } // @brief Arms the PWM outputs that belong to this motor. @@ -62,11 +62,6 @@ void Motor::update_current_controller_gains() { current_control_.i_gain = plant_pole * current_control_.p_gain; } -void Motor::set_current_control_bandwidth(float current_control_bandwidth) { - config_.current_control_bandwidth = current_control_bandwidth; - update_current_controller_gains(); -} - // @brief Set up the gate drivers void Motor::DRV8301_setup() { // for reference: diff --git a/Firmware/MotorControl/motor.hpp b/Firmware/MotorControl/motor.hpp index 89ed74e2..386b0e95 100644 --- a/Firmware/MotorControl/motor.hpp +++ b/Firmware/MotorControl/motor.hpp @@ -95,13 +95,11 @@ public: bool arm(); void disarm(); void setup() { - update_current_controller_gains(); DRV8301_setup(); } void reset_current_control(); void update_current_controller_gains(); - void set_current_control_bandwidth(float current_control_bandwidth); void DRV8301_setup(); bool check_DRV_fault(); void set_error(Error_t error); @@ -211,13 +209,9 @@ public: make_protocol_property("motor_type", &config_.motor_type), make_protocol_property("current_lim", &config_.current_lim), make_protocol_property("requested_current_range", &config_.requested_current_range), - // make_protocol_ro_property("current_control_bandwidth", &config_.current_control_bandwidth) make_protocol_property("current_control_bandwidth", &config_.current_control_bandwidth, [](void* ctx) { static_cast(ctx)->update_current_controller_gains(); }, this) ) - // ), - // make_protocol_function("set_current_control_bandwidth", *this, &Motor::set_current_control_bandwidth, - // "current_control_bandwidth") ); } }; diff --git a/docs/hoverboard.md b/docs/hoverboard.md index 5cf64332..76695be4 100644 --- a/docs/hoverboard.md +++ b/docs/hoverboard.md @@ -16,7 +16,7 @@ The motors are also fairly high inductance, so we need to reduce the bandwidth o ```txt odrv0.axis0.motor.config.resistance_calib_max_voltage = 4 odrv0.axis0.motor.config.requested_current_range = 25 #Requires config save and reboot -odrv0.axis0.motor.set_current_control_bandwidth(100) +odrv0.axis0.motor.config.current_control_bandwidth = 100 ``` Set the encoder to hall mode (instead of incremental). See the [pinout](interfaces.md#hall-feedback-pinout) for instructions on how to plug in the hall feedback. From 59a6d158c414b4a5154f1cff2aea6ea8a2dcf54b Mon Sep 17 00:00:00 2001 From: Oskar Weigl Date: Sun, 30 Sep 2018 19:10:37 -0700 Subject: [PATCH 6/7] add written return value to default_readwrite_endpoint_handler --- CHANGELOG.md | 2 +- Firmware/fibre/cpp/include/fibre/protocol.hpp | 24 ++++++++++++------- 2 files changed, 17 insertions(+), 9 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index aecc53f7..9a53fb02 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -16,7 +16,7 @@ Please add a note of your changes below this heading if you make a Pull Request. * Print function imported from future * Using new hooks to calculate: * `motor.config.current_control_bandwidth` - * This depricates `motor.set_current_control_bandwidth()` + * This deprecates `motor.set_current_control_bandwidth()` * `encoder.config.bandwidth` # Releases diff --git a/Firmware/fibre/cpp/include/fibre/protocol.hpp b/Firmware/fibre/cpp/include/fibre/protocol.hpp index a2d15825..7f9aa992 100644 --- a/Firmware/fibre/cpp/include/fibre/protocol.hpp +++ b/Firmware/fibre/cpp/include/fibre/protocol.hpp @@ -431,8 +431,9 @@ private: typedef std::function EndpointHandler; +// @brief Default endpoint handler for endpoint_ref_t types template -void default_readwrite_endpoint_handler(endpoint_ref_t* value, const uint8_t* input, size_t input_length, StreamSink* output) { +bool default_readwrite_endpoint_handler(endpoint_ref_t* value, const uint8_t* input, size_t input_length, StreamSink* output) { constexpr size_t size = sizeof(value->endpoint_id) + sizeof(value->json_crc); if (output) { // TODO: make buffer size dependent on the type @@ -447,13 +448,17 @@ void default_readwrite_endpoint_handler(endpoint_ref_t* value, const uint8_t* in if (input_length >= size) { read_leendpoint_id)>(&value->endpoint_id, input); read_lejson_crc)>(&value->json_crc, input + 2); + return true; + } else { + return false; } } // @brief Default endpoint handler for const types +// @return: True if endpoint was written to, False otherwise template -std::enable_if_t::value && std::is_const::value> +std::enable_if_t::value && std::is_const::value, bool> default_readwrite_endpoint_handler(T* value, const uint8_t* input, size_t input_length, StreamSink* output) { // If the old value was requested, call the corresponding little endian serialization function if (output) { @@ -463,23 +468,26 @@ default_readwrite_endpoint_handler(T* value, const uint8_t* input, size_t input_ if (cnt <= output->get_free_space()) output->process_bytes(buffer, cnt, nullptr); } + return false; // We don't ever write to const types } // @brief Default endpoint handler for non-const types template -std::enable_if_t::value && !std::is_const::value> +std::enable_if_t::value && !std::is_const::value, bool> default_readwrite_endpoint_handler(T* value, const uint8_t* input, size_t input_length, StreamSink* output) { // Read the endpoint value into output default_readwrite_endpoint_handler(const_cast(value), input, input_length, output); // If a new value was passed, call the corresponding little endian deserialization function uint8_t buffer[sizeof(T)] = { 0 }; // TODO: make buffer size dependent on the type - if (input_length >= sizeof(buffer)) + if (input_length >= sizeof(buffer)) { read_le(value, input); + return true; + } else { + return false; + } } - - template static inline const char* get_default_json_modifier(); @@ -893,8 +901,8 @@ public: list[id] = this; } void handle(const uint8_t* input, size_t input_length, StreamSink* output) final { - default_readwrite_endpoint_handler(property_, input, input_length, output); - if (written_hook_ != nullptr && input_length >= sizeof(TProperty)) { + bool wrote = default_readwrite_endpoint_handler(property_, input, input_length, output); + if (wrote && written_hook_ != nullptr) { written_hook_(ctx_); } } From 88d9eef36814e9315351e59713a82c53d8d247ab Mon Sep 17 00:00:00 2001 From: Oskar Weigl Date: Sun, 30 Sep 2018 19:10:55 -0700 Subject: [PATCH 7/7] reorder for clarity --- Firmware/fibre/cpp/include/fibre/protocol.hpp | 47 +++++++++---------- 1 file changed, 23 insertions(+), 24 deletions(-) diff --git a/Firmware/fibre/cpp/include/fibre/protocol.hpp b/Firmware/fibre/cpp/include/fibre/protocol.hpp index 7f9aa992..e599c0d9 100644 --- a/Firmware/fibre/cpp/include/fibre/protocol.hpp +++ b/Firmware/fibre/cpp/include/fibre/protocol.hpp @@ -431,30 +431,6 @@ private: typedef std::function EndpointHandler; -// @brief Default endpoint handler for endpoint_ref_t types -template -bool default_readwrite_endpoint_handler(endpoint_ref_t* value, const uint8_t* input, size_t input_length, StreamSink* output) { - constexpr size_t size = sizeof(value->endpoint_id) + sizeof(value->json_crc); - if (output) { - // TODO: make buffer size dependent on the type - uint8_t buffer[size]; - size_t cnt = write_leendpoint_id)>(value->endpoint_id, buffer); - cnt += write_lejson_crc)>(value->json_crc, buffer + cnt); - if (cnt <= output->get_free_space()) - output->process_bytes(buffer, cnt, nullptr); - } - - // If a new value was passed, call the corresponding little endian deserialization function - if (input_length >= size) { - read_leendpoint_id)>(&value->endpoint_id, input); - read_lejson_crc)>(&value->json_crc, input + 2); - return true; - } else { - return false; - } -} - - // @brief Default endpoint handler for const types // @return: True if endpoint was written to, False otherwise template @@ -488,6 +464,29 @@ default_readwrite_endpoint_handler(T* value, const uint8_t* input, size_t input_ } } +// @brief Default endpoint handler for endpoint_ref_t types +template +bool default_readwrite_endpoint_handler(endpoint_ref_t* value, const uint8_t* input, size_t input_length, StreamSink* output) { + constexpr size_t size = sizeof(value->endpoint_id) + sizeof(value->json_crc); + if (output) { + // TODO: make buffer size dependent on the type + uint8_t buffer[size]; + size_t cnt = write_leendpoint_id)>(value->endpoint_id, buffer); + cnt += write_lejson_crc)>(value->json_crc, buffer + cnt); + if (cnt <= output->get_free_space()) + output->process_bytes(buffer, cnt, nullptr); + } + + // If a new value was passed, call the corresponding little endian deserialization function + if (input_length >= size) { + read_leendpoint_id)>(&value->endpoint_id, input); + read_lejson_crc)>(&value->json_crc, input + 2); + return true; + } else { + return false; + } +} + template static inline const char* get_default_json_modifier();