Giter Club home page Giter Club logo

Comments (1)

irwineffect avatar irwineffect commented on June 15, 2024

Ryan and I discussed a few ideas yesterday, below are my notes:

Introduction

We are thinking about having a primary setting struct which would be a struct of structs of
fields that operates as a staging area for new settings. The user will define
this structure. Settings change requests from MQTT will operate on this struct,
but the settings will not "go live" until the user initiates a "commit"
request. At this point, the settings framework will trigger an "commit
settings" event. This "update settings" routine would be written by the user, it
will be given the settings structure, the user would use this structure to
populate the individual configurable resources that each task needs.

The Global Setting Structure

This structure would be user-defined. The settings framework would be given an
instance of this struct to store the "staged" settings. We'd like to explore
creating some sort of #derive macro that would let the user define the struct,
and the macro would generate the code needed for the framework to be able to
update the struct. If desired, we'd like to explore a method for the user to be
able to define valid ranges for settings values that would provide automatic
range checking.

Commit Settings

The "commit settings" routine would be responsible for populating the resources
needed by each algorithm. When the user requests settings to be committed, this
routine would be called and given the global setting structure. For example, a
PID controller may have a resource storing the P, I, and D values, and
the update routine would simply need to copy those values from the global
setting structure to the resource. However, in some cases more complex
operations might need to be done, such as performing calculations to derive the
proper values to put in a resource based on the settings. Or, subroutines may
need to be called to configure hardware. This "commit settings" routine would
provide for that flexibility. Additionally, it allows settings updates to be
as atomic as needed with respect to other operations on the device simply by
acquiring locks to the RTIC resources.

MQTT Updates

Still need to figure out the best way to process MQTT requests to update the
settings structure. Suggested solutions:

  1. MQTT requests will be composed of a value and an offset into the settings
    structure. The framework will blindly write this value to the offset in the
    setting structure.
  2. MQTT requests will be composed of a value and a settings identifier of some
    sort (e.g. hierarchical pathname, or a unique ID). The framework will need to
    processes the identifier to determine where in the setting structure to apply
    the value.

The advantage of proposal 1 is that settings updates will be very fast and
require minimal processing on the device. The offsets need to be known to the
configuration software somehow, the most robust system would be for the device
to publish a manifest which maps settings to offset values that the configuration
software uses. This proposal requires the configuration software working
properly to avoid corruption of the settings, a bad offset value could cause
unrelated settings to get modified. Debugging these sorts of issues could
prove challenging. Additionally, because the framework would be blindly
writing values to offsets, no sort of error/range checking would be possible.

Proposal 2 seeks to address the limitations of proposal 1, at the expense of
increased processing responsibility on the device. The device would need to
determine where in the settings structure to write the requested value. This
may be processing intensive, needing much string parsing. However, it opens up
the potential for performing error/range checking.

Another design choice that needs to be evaluated is the granularity of the MQTT
settings requests. Should we have a 1-to-1 mapping of requests to settings
fields, or should it be possible to update multiple settings fields in a single
request, or describe an entire setting structure? Using the simple PID example:

  1. 3 MQTT requests would be required, one for each value.
  2. 1 MQTT request, composed of 3 individual field update requests
  3. 1 MQTT request to update the PID structure, which contains 3 fields

Proposals 1/2 look like they would be simpler to implement, at the expense of
lower throughput if we ever need to do a bulk settings change.

Proposal 3 seeks to correct this issue, but may come at increased complexity,
it still needs to be evaluated. JSON and Serde might make this pretty easy to implement.

Summary

Ideally, the end result would allow us to do roughly something like below:

Creating the settings struct:

// Example Substructure
struct PidSettings {
    p: u32,
    i: u32,
    d: u32,
};
// Primary Settings Structure
#[derive(MqttSettingTrait)]
struct MySettings {
   color: Color,
   pid1: PidSettings,
   pid2: Pidsettings,
}

The Idle task:

// Create an instance of the settings manager
let settings = MqttSettings<MySettings>::new();

// Idle loop
loop {
    // Get messages from MQTT
    let message;
    // Look at the topic prefix to see if we should hand to the settings manager.
    if is_settings_message_topic(message) {
        // Process the settings MQTT request, this will update an internal instance of the MySettings struct
        settings.parse(message);
    }
    // If the message is a request to commit the settings
    if is_commit_message(message) {
        // Schedule the task to commit the settings, pass it a copy of the settings struct
        cx.spawn.commit_settings(settings.get_settings()).unwrap();
    }
}

The commit task:

#[task(resources = [led_driver, pid1_settings, pid2_settings])]
fn commit_settings(cx: commit_settings::Context, new_settings: MySettings) {
    // Use the color setting to change the LED color
    cx.resources.led_driver.lock(|led_driver| {
        // Write to the LEDs
        led_driver.write(new_settings.color);
    });

    // For the PID settings, just copy to the relevant resources
    *cx.resources.pid1_settings = new_settings.pid1;
    // If PID2 used a different structure for it's settings, just drive the From/Into trait
    *cx.resources.pid2_settings = new_settings.pid2.into();
}

External to the device, we publish an MQTT message to the device_identifier/settings/pid1/p topic, then publish to /device_identifier/settings/commit, and the p term of the PID1 setting will be updated, all other settings would maintain their values.

from stabilizer.

Related Issues (20)

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.