diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml new file mode 100644 index 00000000..8d5550d0 --- /dev/null +++ b/.github/workflows/ci.yml @@ -0,0 +1,18 @@ +name: Docker Image CI + +on: + push: + branches: [ "main" ] + pull_request: + branches: [ "main" ] + +jobs: + + build: + + runs-on: ubuntu-latest + + steps: + - uses: actions/checkout@v3 + - name: Build the Docker image + run: docker build -f Dockerfile -t llserver_ecui:$(date +%s) . diff --git a/.vscode/launch.json b/.vscode/launch.json index 41f8d155..afa298fa 100644 --- a/.vscode/launch.json +++ b/.vscode/launch.json @@ -3,16 +3,16 @@ // Hover to view descriptions of existing attributes. // For more information, visit: https://go.microsoft.com/fwlink/?linkid=830387 "version": "0.2.0", - "configurations": [ + "configurations": [ { "name": "(gdb) Launch", "type": "cppdbg", "request": "launch", - "program": "${workspaceFolder}/llserver_ecui_houbolt", + "program": "${workspaceFolder}/build/llserver_ecui_houbolt", "args": [], "stopAtEntry": false, - "cwd": "${workspaceFolder}", - "environment": [], + "cwd": "${workspaceFolder}/build", + "environment": [{"name": "ECUI_CONFIG_PATH", "value": "../../config_ecui"}], "externalConsole": false, "MIMode": "gdb", "setupCommands": [ diff --git a/.vscode/settings.json b/.vscode/settings.json index f95ef421..1ba192f8 100644 --- a/.vscode/settings.json +++ b/.vscode/settings.json @@ -88,5 +88,6 @@ "numbers": "cpp", "semaphore": "cpp", "stop_token": "cpp" - } + }, + "C_Cpp.errorSquiggles": "disabled" } \ No newline at end of file diff --git a/CMakeLists.txt b/CMakeLists.txt index 813fb571..3eb78b41 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -16,7 +16,7 @@ if(NO_PYTHON) add_compile_definitions(NO_PYTHON) list(REMOVE_ITEM sources ${CMAKE_CURRENT_SOURCE_DIR}/src/drivers/PythonController.cpp) else() - include_directories(/usr/include/python3.8) + include_directories(/usr/include/python3.10) endif() add_executable(${PROJECT_NAME} ${sources}) @@ -43,48 +43,8 @@ if(LINUX) target_link_libraries(${PROJECT_NAME} PRIVATE -lcanlib) endif() if(NOT NO_PYTHON) - target_link_libraries(${PROJECT_NAME} PRIVATE -lpython3.8) + target_link_libraries(${PROJECT_NAME} PRIVATE -lpython3.10) endif() else() target_link_libraries(${PROJECT_NAME} PRIVATE Threads::Threads) endif() - - -##----WITH BOOST -# cmake_minimum_required(VERSION 3.13) -# project(llserver_ecui_houbolt) - -# find_package(Threads REQUIRED) - -# set(CMAKE_CXX_STANDARD 17) -# set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -Wall") - -# #if(NOT TARGET spdlog) -# # # Stand-alone build -# # find_package(spdlog REQUIRED) -# #endif() - -# include_directories(include) - -# file(GLOB sources ./*.cpp src/*.cpp include/*.h) - -# set(Boost_USE_STATIC_LIBS OFF) -# set(Boost_USE_MULTITHREADED ON) -# set(Boost_USE_STATIC_RUNTIME OFF) -# find_package(Boost 1.45.0 COMPONENTS system) - -# if(Boost_FOUND) -# add_executable(${PROJECT_NAME} ${sources}) -# #spdlog_enable_warnings(${PROJECT_NAME}) - - -# if(UNIX AND NOT APPLE) -# set(LINUX TRUE) -# endif() - -# if(LINUX) -# target_link_libraries(${PROJECT_NAME} PRIVATE Threads::Threads -lstdc++fs Boost::system)#spdlog::spdlog) -# else() -# target_link_libraries(${PROJECT_NAME} PRIVATE Threads::Threads Boost::system)#spdlog::spdlog) -# endif() -# endif() diff --git a/Dockerfile b/Dockerfile index 8587575a..f268bc89 100644 --- a/Dockerfile +++ b/Dockerfile @@ -1,17 +1,42 @@ -FROM ubuntu:20.04 +# specify the node base image with your desired version node: +FROM ubuntu -# Replace shell with bash so we can source files -RUN rm /bin/sh && ln -s /bin/bash /bin/sh -# Set debconf to run non-interactively -RUN echo 'debconf debconf/frontend select Noninteractive' | debconf-set-selections +WORKDIR /home -# Install base dependencies -RUN apt-get update && apt-get install -y -q --no-install-recommends \ - git \ - cmake \ - build-essential -WORKDIR /llserver_ecui_houbolt +### KVASER Driver -CMD ["bash"] +RUN apt-get update +RUN apt-get install -y git +RUN apt-get install -y build-essential +RUN apt-get install -y linux-headers-`uname -r` +RUN apt-get install -y cmake make +RUN apt-get install -y wget +RUN apt-get install -y python3.10-dev + +RUN wget --content-disposition "https://www.kvaser.com/downloads-kvaser/?utm_source=software&utm_ean=7330130980754&utm_status=latest" +RUN tar xvzf linuxcan.tar.gz +WORKDIR /home/linuxcan/canlib +RUN make +RUN make install +RUN /usr/doc/canlib/examples/listChannels + +WORKDIR /home/ + +# Clone the conf files into the docker container +ADD ./ /home/llserver_ecui_houbolt +WORKDIR /home/llserver_ecui_houbolt + +RUN git submodule init +RUN git submodule update + +RUN mkdir -p build +WORKDIR /home/llserver_ecui_houbolt/build + +RUN cmake -D NO_PYTHON=false -D NO_CANLIB=false -S ../ -B ./ +RUN make -j + +ENV ECUI_CONFIG_PATH=/home/config_ecui + +ENTRYPOINT ./llserver_ecui_houbolt \ No newline at end of file diff --git a/README.md b/README.md index e2b4ed3e..ebfb0635 100644 --- a/README.md +++ b/README.md @@ -1,19 +1,657 @@ -# Low Level Server for the Engine Control User Interface +

Low Level Server for the SpaceTeam Mission Control System

-## Links +

Table of Contents

-Documentation of whole ECUI and Setup Guide -### [TXV_ECUI_WEB](https://github.com/SpaceTeam/TXV_ECUI_WEB/tree/dev) +- [Overview](#overview) +- [Requirements](#requirements) +- [Installation](#installation) + - [Build options](#build-options) + - [Supported CAN Drivers](#supported-can-drivers) +- [CAN Protocol](#can-protocol) +- [The importance of States](#the-importance-of-states) +- [Events](#events) + - [State to CAN Command](#state-to-can-command) + - [State to State](#state-to-state) + - [Trigger Types](#trigger-types) +- [Configuration](#configuration) + - [config.json](#configjson) + - [mapping.json](#mappingjson) + - [CANMapping](#canmapping) + - [DefaultEventMapping](#defaulteventmapping) + - [EventMapping](#eventmapping) + - [GUIMapping](#guimapping) +- [Autonomous Control Test Sequence](#autonomous-control-test-sequence) + - [`globals` section](#globals-section) + - [`data` section](#data-section) + - [Abort Sequence Format](#abort-sequence-format) +- [TCP Socket Message Types](#tcp-socket-message-types) +- [UDP Socket Endpoint for LoRa](#udp-socket-endpoint-for-lora) + - [LoRa Config](#lora-config) +- [Troubleshooting](#troubleshooting) -Temperature Sensors over Ethernet with Siliconsystems TMP01 +## Overview -### [TXV_ECUI_TMPoE](https://github.com/SpaceTeam/TXV_ECUI_TMPoE/tree/master) +The SpaceTeam Mission Control System (STMC) Suite consists of multiple programms that +form a system for Monitoring and Remote Control Purposes. Historically it was developed +for Testing Rocket Engines and has then been further extended to be usable as a MissionControl +Interface. For further information follow [SpaceTeam Mission Control System](...) -![LLServer Diagram](img/llserver.png) +**The Low Level Server is responsible for handling and processing all time critical tasks** -# Notes: +This includes the implementation of +- our own [CAN Protocol](https://github.com/SpaceTeam/can_houbolt) +- a possible UDP endpoint for using our CAN Protocol in an optimized way using + our custom LoRa shield with a custom LoRa Driver (will get public soon) +- the Database Interface (influxDB) +- the Control Sequence Logic +- the Interface to our own [Webserver](https://github.com/SpaceTeam/web_ecui_houbolt) + +The complexity of this program lies in the various configurable +options for initialization and during runtime. They are split into two files that +**must** must reside in the same directory: + +- config.json - the config file for socket endpoints, sampling rates, CAN bus params, etc. +- mapping.json + - [CANMapping](#canmapping) + - [DefaultEventMapping](#defaulteventmapping) + - [EventMapping](#eventmapping) + - [GUIMapping](#guimapping) + +In our setup these files can be found in [config_ecui](https://github.com/SpaceTeam/config_ecui), but this is not mandatory. +The config file directory path can be set either by passing it on start as an argument +or by setting the environment variable **ECUI_CONFIG_PATH**. The argument has +priority over the environment variable. + +## Requirements + +>Note: If you would like to use the llserver out of the box you also need to +install our webserver and a bunch of other tools. But don't worry, **we've written +an easy to setup guide in our [config_ecui](https://github.com/SpaceTeam/config_ecui) +repository.** Otherwise you first need to implement a tcp server with our communication +protocol in order to start receiving data. + +The simplest way to use the llserver is by setting it up inside a docker container +in that case docker engine needs to be preinstalled. + +First you need to install an influxdb (docker container recommended) + +## Installation + +To install the llserver using docker you can run +``` +sudo chmod +x install.sh +./install.sh +``` + +This script generates and mounts a config folder in the parent directory named +config_ecui where the [config.json](#configjson) and [mapping.json](#mappingjson) files must be present. + +### Build options +The project uses cmake for compiling. You can provide different build options to +cmake using the `-D` option: + +- `-D NO_PYTHON=[true | false]` +- `-D NO_CANLIB=[true | false]` + +Setting one of these build flags result in not binding the corresponding libraries +to avoid a compile error. If you would like to change one of these settings checkout +the Entrypoint line in the Dockerfile + +>NOTE: different build modes require different config variables, make sure you +have definded all of them properly. See [config_ecui](https://github.com/SpaceTeam/config_ecui). + +### Supported CAN Drivers +Currently two drivers are supported namely +- [Kvaser CANLIB](https://www.kvaser.com/canlib-webhelp/page_canlib.html) +- [SocketCAN](https://docs.kernel.org/networking/can.html) + +the preferred driver can be selected inside the [config.json](#configjson). +The Dockerfile also installs all required kvaser canlib library files automatically. + +## CAN Protocol +As many terms from the [CAN Protocol](https://github.com/SpaceTeam/can_houbolt) +are also used to describe many functionalities +in the llserver, it is recommended to read through this documentation first before +you continue. + +The llserver keeps a hashmap of all commands that are supported of the connected +channels. These are used in the event mapping and control sequences to +send commands to the hardware. + +## The importance of States +The llserver manages a hashmap filled with states which is called the +**State Controller**. Basically every variable inside the system is represented +as a double value inside the state controller. This includes user inputs. + +Each entry consists of a + +- state name - as key +- value - as double +- timestamp - 0 when uninitialized else timestamp of the last change +- dirty flag - used for transmitting periodic status updates to the web server + +We follow a naming convention which mostly boils down to + +`prefix:channel_name:state` + +as the `prefix` it is often used `gui` as all user inputs are also tracked in the +state controller and logged to the database. In case if something goes wrong we can +analyze whether a wrong user input was made or another event caused the trouble. +**User inputs must be prefixed with `gui` in order to be processed correctly.** + +Despite our naming convetion of state names, one can input a state name +with as many `":"` dividers as desired. + +>WARNING: Although a `:` is used to make the state names more readable and +processable it shall be pointed out that this notation is not supported in +html. Hence all `:` are translated to `-` when received at the web client. + +## Events +Another key feature of the llserver is the event system. An event can be triggered +when a specific state changes its value. This is used for translating user inputs +to CAN commands that are transmitted over the CAN bus for example. But it is also +possible to trigger an event based on a sensor value or actuator state +of a specific hardware channel (since they +are all represented as states). For this behaviour to work there are two types of events + +### State to CAN Command + +``` +"gui:Flash:Clear": [ + { + "command": "ecu:RequestFlashClear", + "parameters": [] + }, + { + "command": "pmu:RequestFlashClear", + "parameters": [] + }, + { + "command": "rcu:RequestFlashClear", + "parameters": [] + } +] +``` +In this example the `gui:Flash:Clear` state indicates a button press on the user interface. When it is pressed, a request to clear the flash of each electronics board +(ecu, pmu, rcu) shall be transmitted. The `parameters` entry allows for additional +arguments that may be required depending on the specified command. When +a string is located inside the parameters list, the llserver tries to resolve it +as a state inside the state controller and use its value instead. This is especially +useful for analog user inputs. + +### State to State +``` +"ecu:FlashStatus": [ + { + "state": "gui:Flash:Clear", + "triggerType": "!=", + "triggerValue": 0, + "value": 0 + } +] +``` + +In bot cases it is possible to trigger multiple actions in one go as seen in the +example of `gui:Flash:Clear`. Also in both cases it is possible to specify a triggerType. + +### Trigger Types +Each event entry can include a `triggerType` with an additional `triggerValue`. +This is needed if the event shall only +be triggered when certain conditions are met, not everytime the state gets changed. +Possible trigger types are: + +- `==` --> triggers when the state value equals the `triggerValue` +- `!=` --> triggers when the state value not equals the `triggerValue` +- `>=` --> triggers when the state value is greater or equal than the `triggerValue` +- `<=` --> triggers when the state value is smaller or equal than the `triggerValue` +- `>` --> triggers when the state value greater than the `triggerValue` +- `<` --> triggers when the state value smaller than the `triggerValue` + +>NOTE: An event with a triggerType is only triggered when the previous value +was outside the trigger range! In this way the event only gets triggered when +the value changes from outside the trigger range to the inside of the trigger range which +means that if the value remains inside the trigger range over a long period the event +only gets triggered once. + +Example: +``` +"gui:fuel_main_valve:checkbox": [ + { + "command": "fuel_main_valve:SetTargetPosition", + "triggerType": "==", + "triggerValue": 0, + "parameters": [0] + }, + { + "command": "fuel_main_valve:SetTargetPosition", + "triggerType": "!=", + "triggerValue": 0, + "parameters": [65535] + } +] +``` +In this case the gui element for the fuel main valve is represented as a checkbox. +when the checkbox gets pressed, the fuel main valve opens completely. Otherwise +the valve closes completely. When multiple actions per state exist, the program +processes them step by step, as defined in the json array. **So be reminded that +a different order can cause different behaviours for more complex event mappings.** + +>NOTE: the fuel_main_valve gui button and hardware channel have no relation at the +beginning. Only an entry in the EventMapping links them together. + +## Configuration + +### config.json + +In the config.json file all variables are defined that are important for the +initialization process of the llserver. A complete example config file with +all possible entries can be viewed in the [config_ecui](https://github.com/SpaceTeam/config_ecui) repo. + +### mapping.json + +The mapping.json file consists of four different parts. Each one must be at least +declared as an empty object, i.e. + +``` +{ + "CANMapping": {}, + "DefaultEventMapping": {}, + "EventMapping": {}, + "GUIMapping": {} +} +``` +#### CANMapping + +``` +"CANMapping": { + "7": { + "0": { + "offset": 0, + "slope": 0.00010071, + "stringID": "pmu_5V_voltage" + }, + "1": { + "offset": 0, + "slope": 0.00010071, + "stringID": "pmu_5V_high_load_voltage" + }, + "2": { + "offset": 0, + "slope": 0.00033234, + "stringID": "pmu_12V_voltage" + } + "stringID": "pmu" + } + }, +``` +Since in a CAN Network multiple **Nodes** comunicate with each other using IDs, +we want to assign readable names to each node and each channel, so we +can work with them more easily. +A node entry starts with its unique identifier as a key and contains an object, +with arbitrary many channel entries. Each channel has a `:sensor` state that +can be scaled with the two entries `offset` and `slope`. The readable name +is defined with `stringID`. +A specification of the channel type is not needed since this information is loaded +when the nodes get initialized. + + +#### DefaultEventMapping + +The default event mapping can be used to define generic behaviour for gui elements +acting on hardware channels. +``` +"DefaultEventMapping": { + "DigitalOut": [ + { + "command": "DigitalOut:SetState", + "parameters": [ + "DigitalOut" + ] + } + ], + "Servo": [ + { + "command": "Servo:SetTargetPosition", + "parameters": [ + "Servo" + ] + } + ] +} +``` +The default behaviour for a gui element can be overwritten by an entry +in the event mapping. The key of an action may be an hardware channel type +which defines an action for each hardware channel of this type. The +channel type name can be also used to describe the command and parameters. +This gets then replaced with the actual channel name that is currently processed. + +#### EventMapping +``` +"EventMapping": { + "gui:Flash:Clear": [ + { + "command": "ecu:RequestFlashClear", + "parameters": [] + }, + { + "command": "pmu:RequestFlashClear", + "parameters": [] + }, + { + "command": "rcu:RequestFlashClear", + "parameters": [] + } + ] +} +``` +An entry in the event mapping prevents default behaviours defined in the +DefaultEventMapping from being triggered. For further information about +events go to the [Events](#events) section. +#### GUIMapping +``` +"GUIMapping": [ + { + "label": "Fuel Tank Pressure", + "state": "fuel_tank_pressure:sensor" + }, + { + "label": "Ox Tank Pressure", + "state": "ox_tank_pressure:sensor" + }, + { + "label": "Supercharge Valve", + "state": "supercharge_valve:sensor" + } +] +``` + +The GUI Mapping is a config option to tell the user interface, how a gui element +with a certain state shall be named in an even more human readable way as state names. +This information only gets transmitted to the user interface and has no implications +on the llserver. + +## Autonomous Control Test Sequence + +To be able to test a liquid engine it is normally required to execute multiple commands +in a very short amount of time (pressurization, ignition, engine ramp-up, etc.). + +For this purpose a sequence manager has been developed for automatic test sequences. + +Test Sequences are defined inside the `$ECUI_CONFIG_PATH/sequences/` folder. +Each sequence uses the JSON format and consists of two main objects: +- `globals` - general definitions used for the sequence processing +- `data` - the actual sequence + +### `globals` section +Inside the `globals` section following entries are needed + +| key | type | value | +| ----------------- | ------ | -------------------------------------------------------------------------------------------------------------------------- | +| `"startTime"` | float | relative start of the squence (may also be negative) | +| `"endTime"` | float | relative end of the sequence | +| `"interpolation"` | object | object with command name as key and either `"none"`(step function behaviour) or `"linear"`(linear interpolation) as values | +| `"interval"` | float | time precision of each iteration step | +| `"ranges"` | array | list of state names used for range checking | + +The interpolation entry specifies the behaviour between datapoints of the sequence. +The range entry is used to specify each state used for range checking. This means that at each datapoint a range can be +set in which the specified sensor must reside. If the sensor value gets out of range and **autoabort** is active inside the config.json +the sequence gets aborted instantly. + +### `data` section + +The data section includes a list of **command group**. These can be +used to group multiple datapoints relatively to one timestamp in order +to be moved more easily along the time axis if for example the burntime changes. + +Each group command includes + | key | type | value | + | ------------- | --------------- | ----------------------------------------------------------------------------------------------------------------------------- | + | `"timestamp"` | string or float | if timestamp is string only `"START"` or `"END"` are allowed which get replace by `"startTime"` and `"endTime"` respectively. | + | `"name"` | string | name of the command group | + | `"desc"` | string | description | + | `"actions"` | array | list of datapoints with relative timestamp to command group | + | | + + +Each datapoint may include + | key | type | value | + | ---------------------- | --------------- | ---------------------------------------------------------------------------------------------------------------- | + | `"timestamp"` | float | timestamp relative to command group (here **only floats are valid!**) | + | `""` | array of floats | parameters for the specific command | + | `"sensorNominalRange"` | object | states as keys and array of two elements with range as values (must be defined in the global section `"ranges"`) | + + +The first datapoint of the first command group **HAS TO** include all commands used in the sequence for proper initialization! +Each number in actions except the timestamp is double on the LLServer. + +> Note: The keywords "START" or "END" are only allowed in the Group Commands (objects inside data array). +> +Example: +``` +{ + "globals": + { + "endTime": 15, + "interpolation": + { + "fuel_main_valve:SetTargetPosition": "linear", + "ox_main_valve:SetTargetPosition": "linear", + "igniter:SetState": "none" + }, + "interval": 0.01, + "ranges": + [ + "chamberPressure:sensor" + ], + "startTime": -10 + }, + "data": + [ + { + "timestamp": "START", + "name": "start", + "desc": "set all to initial state", + "actions": + [ + { + "timestamp": 0.0, + "fuel_main_valve:SetTargetPosition": [0], + "ox_main_valve:SetTargetPosition": [0], + "igniter:SetState": [0], + "sensorsNominalRange": + { + "chamberPressure:sensor": [-5, 20] + } + } + ] + }, + { + "timestamp": -3.0, + "name": "ignition", + "desc": "lets light this candle", + "actions": + [ + { + "timestamp": 0, + "igniter:SetState": [100] + } + ] + }, + { + "timestamp": 0.0, + "name": "engine startup", + "desc": "ramp up engine", + "actions": + [ + { + "timestamp": 0, + "fuel_main_valve:SetTargetPosition": [0], + "ox_main_valve:SetTargetPosition": [0] + }, + { + "timestamp": 0.5, + "ox_main_valve:SetTargetPosition": [15000], + "fuel_main_valve:SetTargetPosition": [15000] + }, + { + "timestamp": 1.2, + "fuel_main_valve:SetTargetPosition": [25000], + "ox_main_valve:SetTargetPosition": [25000] + }, + { + "timestamp": 1.5, + "igniter:SetState": [0] + }, + { + "timestamp": 1.7, + "fuel_main_valve:SetTargetPosition": [100], + "ox_main_valve:SetTargetPosition": [100] + } + ] + }, + { + "timestamp": 10.0, + "name": "shutdown", + "desc": "engine shutdown", + "actions": + [ + { + "timestamp": 0, + "fuel_main_valve:SetTargetPosition": [100], + "ox_main_valve:SetTargetPosition": [100] + }, + { + "timestamp": 0.7, + "fuel_main_valve:SetTargetPosition": [0], + "ox_main_valve:SetTargetPosition": [0] + } + ] + }, + { + "timestamp": "END", + "name": "end", + "desc": "the end", + "actions": + [ + { + "timestamp": 0.0, + "fuel_main_valve:SetTargetPosition": [0], + "ox_main_valve:SetTargetPosition": [0] + } + ] + } + ] +} +``` + +### Abort Sequence Format + +Another feature is the ability to define a **"safe state"** to be +executed in order the test control sequence fails or gets aborted. + +Test Abort Sequence is defined inside the `$ECUI_CONFIG_PATH/sequences/abort_sequences/` folder. Currently only one abort sequence is supported and +must be named `AbortSequence.json`. + +For now exactly one object with all commands to be executed. +The `"endTime"` key in `"globals"` is used to describe for how long the logging should continue +in case of an abort. + + { + "globals": { + "endTime": 3.2 //double + }, + "actions" : { + "fuel_main_valve:SetTargetPosition": [0], //array[double] + "igniter:SetState": [0], //array[double] + "ox_main_valve:SetTargetPosition": [0] //array[double] + } + } + +## TCP Socket Message Types + +In order to communicate with the webserver, a tcp socket connection is +established. **It is mandatory to send the llserver specific messages +to initate state transmission and start test control sequences.** + +For the whole API documentation refer to [Webserver](https://github.com/SpaceTeam/web_ecui_houbolt) + +## UDP Socket Endpoint for LoRa + +This protocol is based on our [CAN Protocol](#can-protocol). + +This implementation uses LoRa as an unidirectional method for receiving +data from the rocket during flight. For receiving LoRa messages a custom +LoRa shield is used on a raspberry pi. (Repo coming soon) +A UDP socket connection is used for data transmission between llserver and +raspberry pi. + +After the internal control +of the rocket takes over and no further commands are sent to the rocket +the only message type that the rocket sends automatically and periodically +is the `DataMsg_t` of each Generic Channel. This means we can strip the LoRa +message down to only data messages and can even combine them into one large +message. This is done on our RCU (Radio Control Unit) which listens to the +CAN FD bus for any data messages and updates a buffer which is split into +as many regions as generic channels exists inside the rocket (number of CAN +nodes). + +Since the data message length is highly variable and considered to be +specified within the channel_mask, the header alone takes up an unnessesary +large amount of bytes that can be considered "constant" during +flight. Therefore the CAN header + data message header gets removed +for the LoRa messages +and is statically entered inside the [config.json](#configjson). + +There is only one additional byte for each generic channel which indicates if the +section contains valid data. **THIS BYTE IS NOT INCLUDED IN THE CONFIG canMsgSize ENTRY!** + +### LoRa Config + +The `LORA` section in the [config.json](#configjson) includes + +``` +"LORA": { + "ip": "192.168.1.7", + "port": 5001, + "nodeIDsRef": [6, 8], + "nodeIDs": [16, 18], + "canMsgSizes": [54, 39] +} +``` + +The `ip` and `port` describe the udp endpoint to the raspberry pi. + +The `nodeIDsRef` array defines the corresponding node ids on the CAN FD bus. This +is needed since the LoRa messages are injected in the CAN Manager as normal CAN messages +and therefore need to load the correct CAN header before the message is injected. This +means that the hardware **MUST** be connected over the CAN FD bus for the initialization +of the llserver in order to initialize the nodes correctly. Otherwise the LoRa messages cannot +be decoded and are lost! + +The `nodeIDs` array contains the node ids for the LoRa channels (in this case CAN FD bus node ids +prepended with 1) + +The `canMsgSizes` array contains the message size of each can data message (**HEADER BYTE EXCLUDED**) + + +>NOTE: that depending on the total message length, the LoRa driver on +the raspberrypi must be configured correctly as well. See (LoRa doc coming +soon...) + + +## Troubleshooting - Every Sequence needs to define each device at the "START" timestamp - **Make sure every "sensorsNominalRange" object in the sequence contains ALL sensors, with a range -specified** \ No newline at end of file +specified** + + +- if the llserver fails to connect to the web server or carshes instantly try +to check if the correct ip addresses are used in the config file with +`sudo docker network inspect bridge` + +- if either or both web and llserver refuse to start, try and check the docker environment variable for the correct config path + +- if the llserver crashes instantly check if influx is correctly installed \ No newline at end of file diff --git a/ecui-llserver.service b/ecui-llserver.service deleted file mode 100644 index 7ea5b0d4..00000000 --- a/ecui-llserver.service +++ /dev/null @@ -1,15 +0,0 @@ -Description=Service for ECUI Low Level Server - -Wants=network.target -After=syslog.target network-online.target - -[Service] -Type=simple -ExecStart=/home/pi/llserver_ecui_houbolt/llserver_ecui_houbolt -WorkingDirectory=/home/pi/llserver_ecui_houbolt/ -Restart=always -RestartSec=10 -KillMode=process - -[Install] -WantedBy=multi-user.target diff --git a/img/llserver.pdf b/img/llserver.pdf deleted file mode 100644 index d05b8791..00000000 Binary files a/img/llserver.pdf and /dev/null differ diff --git a/img/llserver.png b/img/llserver.png deleted file mode 100644 index ffe6ce54..00000000 Binary files a/img/llserver.png and /dev/null differ diff --git a/img/stAscii.txt b/img/logo_short.txt similarity index 100% rename from img/stAscii.txt rename to img/logo_short.txt diff --git a/img/txvAscii.txt b/img/txvAscii.txt deleted file mode 100644 index 58f0b5da..00000000 --- a/img/txvAscii.txt +++ /dev/null @@ -1,49 +0,0 @@ -                           ˭ʻ ˣ˙                           -                          ˂ĩ  ˙o˙                          -                         ˑæ˙   ʳw˙                         -                        ˛Ǭ˂     }ł                         -                       ˙8o      ˙Ņc                        -                       İÑ˙       |¶"                       -                      ɹŴ^         KŇ˝                      -                     °¶À          ʹ¶9˙                     -                    ˙BŴ,           eŴl                     -                    ļŴÏ            `Ŋ¶-                    -                   ˞¶¶˘             ɨŴǡ                    -                   KŴŶ              ´WŴ|                   -                  ˣŴŴ-               (Ŵģ˙                  -                  ÂŴX                ˓¶Ŵɹ                  -                 ˣŴŴˣ                 ÞŴģ˙                 -                 ĒŴ@˙                 ˢŴŴ²                 -                -ŴŴŦ                  ˙MŴÁ                 -                țŴŴ"                   õŴŴ˞                -               ˙MŴŊ˙                   =ŴŴĊ                -               ɿŴŴæ                    ¯ŴŴÑ˙               -               wŴŴC                     ǸŴŴˣ               -              ˙¶ŴŴ¡                     KŴŴ£               -              ɿŴŴŴ-                     }ŴŴÑ˙              -              EŴŴ¶˙                     cŴŴŴ˂              -            ˙ɿŊŴŴÑ                      ʸŴŴŴ#˘             -           ˣǑŴŴŴŴs                      ´ǬŴŴŴ¶eʿ           -         ,æŴŴŴŴŴĴ                        ˆ0ŴŴŴŴŊT˙         -       -UŴŴŴŴŴŴa˙                         ˘ÑŴŴŴŴŴŇĩ˙       -     .3¶ŴŴŴŴŴŴÎ˙                           ˑMŴŴŴŴŴŴğ+˙     -    ´ŇŴŴŴŴŴŴŴd˙                             ˭WŴŴŴŴŴŴŴf     -    ĊŴŴŴŴŴŴŴĒ˙                               ʳŊŴŴŴŴŴŴ¶ʻ    -   ʽ¶ŴŴŴŴŴŴȔ˙                                 "¶ŴŴŴŴŴŴG    -   ÎŴŴŴŴŴŴŴˣ                                  ˙dŴŴŴŴŴŴŴ,   -  ˂ŴŴŴŴŴŴŴŴŴÇ´                               ˣģŴŴŴŴŴŴŴŴÛ   -  ÀŴŴŴŴŴŴŴŴŴŴWĿ´                           ,ãŴŴŴŴŴŴŴŴŴŴŴʺ  - |ŴŴŴŴŴŴŴŴŴŴŴŴŴ¶ű,                      ˙ªÒŴŴŴŴŴŴŴŴŴŴŴŴŴŔ˙ -˙ģŴŴŴŴŴŴŴŴŴŴŴŴŴŴŴŴĤlʿ                 ˂¤WŴŴŴŴŴŴŴŴŴŴŴŴŴŴŴŴ? -ĩŴŴŴŴŴŴŴŊ@ĂǩµʪLJrJÞŎ¶¶Ē=˙           -ɨɱŴŇÁŢĩcs¤ħÀŔҶŴŴŴŴŴŴŇ -ƆŦLJɹʺ˂ˆ˙           ˙-ɿɨòĿɾˈ     -ɹɁİʖˣ´           ˙´ˑ˥^cCł -                         ˙ʼ˙   ˙.                          -                                                           -                                                           -                                                           -    ======              II  II              `I    I´ -        II                 IIII                II  II  -        II                 `II´                `I  I´  -        II                  II                  IIII   -        II                 IIII                 `II´ -        II                II  II                 II          diff --git a/img/txvLogo.txt b/img/txvLogo.txt deleted file mode 100644 index 3408d2cc..00000000 --- a/img/txvLogo.txt +++ /dev/null @@ -1,37 +0,0 @@ -                    ˂´´˂                     -                   ˣ^  ı"                    -                  :ě˙  ˙ħ°                   -                 ˓ð-    ʹǢ´                  -                ˙Æļ      )Ē˙                 -                t@˙      ˙Ñį                 -               ˤŴ÷        =¶,                -              ˙ɱǑ˙        ˙©Ŏ˙               -              įŴˢ          ɾŴc               -             ´Ŋġ           ˙ŔM´              -             ƆŴª            ?ŴJ              -            ˙ŊW˙            ˙¶Ň˙             -            ĩŴE              wŴ=             -            QŴ^              rŴÄ             -           ,ŴŴ´              ʻŴŴ-            -           țŴǬ                ÑŴC            -          ˙ŅŴ¢                #ŴǢ            -          ˭ŴŴĊ                3ŴŴˀ           -         :$ŴŴc                LJŴŴæʹ          -       ˀõŴŴŴÒ˙                ´ƌŴŴ¶£¸        -     ˓2¶ŴŴŴǑ´                  `ǢŴŴŴ¶F´      -   ˙ĹŊŴŴŴŴ%´                    ˝ǬŴŴŴŴǾɺ˙    -   ċŴŴŴŴŴɱ˒                      ʼŅŴŴŴŴŴ=    -  ´ŊŴŴŴŴ@¯                        -ÑŴŴŴŴǸ˙   -  IŴŴŴŴŴ3˙                        ˙UŴŴŴŴŴį   - -¶ŴŴŴŴŴŴǬ²˙                    ˙<ǸŴŴŴŴŴŴŊ`  - ¥ŴŴŴŴŴŴŴŴŴŔì´                ´*ģŴŴŴŴŴŴŴŴŴʧ  -ˤŴŴŴŴŴŴŴŴŴŴŴŴ¶õˣ˙          ˙ʵê¶ŴŴŴŴŴŴŴŴŴŴŴ¶- -ĒŅǣǡõoJ?!ʳˀ˙ʽ!ćPã)ˤ˙    ˙"fAÎįʸˆ˙-ˤ²?ĿĴP6BǸñ -                 ˙˞˭˙  ˙,-˙                  -                                             -                                             -    ˝ˣrˢ~          ¸˂  ʸ˙          ʸ˙  ʸ     -      Ŧ¸            LJ°ıʵ           ºʺ '7     -      Ŧ¸            ˙P?            ˙¤ Ċ´     -      Ŧ¸            ¦=Ɂ´            ?ʵs      -      ȓ˛           ¯į ´C˙           ˙Ȕʽ      diff --git a/img/txvLogoSquashed.txt b/img/txvLogoSquashed.txt deleted file mode 100644 index 214e40d3..00000000 --- a/img/txvLogoSquashed.txt +++ /dev/null @@ -1,29 +0,0 @@ -                    ˂´´˂                     -                   ˣ^  ı"                    -                  :ě˙  ˙ħ°                   -                 ˓ð-    ʹǢ´                  -                ˙Æļ      )Ē˙                 -               ˤŴ÷        =¶,                -              ˙ɱǑ˙        ˙©Ŏ˙               -              įŴˢ          ɾŴc               -             ´Ŋġ           ˙ŔM´              -            ˙ŊW˙            ˙¶Ň˙             -            ĩŴE              wŴ=             -           ,ŴŴ´              ʻŴŴ-            -          ˙ŅŴ¢                #ŴǢ            -         :$ŴŴc                LJŴŴæʹ          -       ˀõŴŴŴÒ˙                ´ƌŴŴ¶£¸        -     ˓2¶ŴŴŴǑ´                  `ǢŴŴŴ¶F´      -   ˙ĹŊŴŴŴŴ%´                    ˝ǬŴŴŴŴǾɺ˙    -   ċŴŴŴŴŴɱ˒                      ʼŅŴŴŴŴŴ=    -  IŴŴŴŴŴ3˙                        ˙UŴŴŴŴŴį   - ¥ŴŴŴŴŴŴŴŴŴŔì´                ´*ģŴŴŴŴŴŴŴŴŴʧ  -ˤŴŴŴŴŴŴŴŴŴŴŴŴ¶õˣ˙          ˙ʵê¶ŴŴŴŴŴŴŴŴŴŴŴ¶- -ĒŅǣǡõoJ?!ʳˀ˙ʽ!ćPã)ˤ˙    ˙"fAÎįʸˆ˙-ˤ²?ĿĴP6BǸñ -                 ˙˞˭˙  ˙,-˙                  -                                             -                                             -    =====          `I  I´          `I   I´     -      I             `II´            I. .I     -      I             .II.            `I I´     -      I            .I I.             Y     diff --git a/include/can/Channel.h b/include/can/Channel.h index f193c63b..98727748 100644 --- a/include/can/Channel.h +++ b/include/can/Channel.h @@ -56,7 +56,7 @@ class Channel double result = value; if (a != 1 || b != 0) { - result = value / a + b; + result = (value - b) / a; } return result; }; diff --git a/include/can/PIControl.h b/include/can/PIControl.h new file mode 100644 index 00000000..b1e250a0 --- /dev/null +++ b/include/can/PIControl.h @@ -0,0 +1,77 @@ +// +// Created by Markus on 03.09.21. +// + +#ifndef LLSERVER_ECUI_HOUBOLT_PI_CONTROL_H +#define LLSERVER_ECUI_HOUBOLT_PI_CONTROL_H + +#include "can/Channel.h" +#include "can/Node.h" +#include "can_houbolt/channels/pi_control_channel_def.h" + +class PIControl : public Channel, public NonNodeChannel +{ +public: + //TODO: MP check if this is the only and correct way to implement static const with inheritation + static const std::vector states; + static const std::map> scalingMap; + static const std::map variableMap; + + //-------------------------------RECEIVE Functions-------------------------------// + +public: + PIControl(uint8_t channelID, std::string channelName, std::vector sensorScaling, Node *parent); + + std::vector GetStates() override; + + //-------------------------------RECEIVE Functions-------------------------------// + + void ProcessCANCommand(Can_MessageData_t *canMsg, uint32_t &canMsgLength, uint64_t ×tamp) override; + + //-------------------------------SEND Functions-------------------------------// + + void SetEnabled(std::vector ¶ms, bool testOnly); + void GetEnabled(std::vector ¶ms, bool testOnly); + + void SetTarget(std::vector ¶ms, bool testOnly); + void GetTarget(std::vector ¶ms, bool testOnly); + + void SetP_POS(std::vector ¶ms, bool testOnly); + void GetP_POS(std::vector ¶ms, bool testOnly); + + void SetI_POS(std::vector ¶ms, bool testOnly); + void GetI_POS(std::vector ¶ms, bool testOnly); + + void SetP_NEG(std::vector ¶ms, bool testOnly); + void GetP_NEG(std::vector ¶ms, bool testOnly); + + void SetI_NEG(std::vector ¶ms, bool testOnly); + void GetI_NEG(std::vector ¶ms, bool testOnly); + + void SetSensorSlope(std::vector ¶ms, bool testOnly); + void GetSensorSlope(std::vector ¶ms, bool testOnly); + + void SetSensorOffset(std::vector ¶ms, bool testOnly); + void GetSensorOffset(std::vector ¶ms, bool testOnly); + + void SetOperatingPoint(std::vector ¶ms, bool testOnly); + void GetOperatingPoint(std::vector ¶ms, bool testOnly); + + void SetActuatorChannelID(std::vector ¶ms, bool testOnly); + void GetActuatorChannelID(std::vector ¶ms, bool testOnly); + + void SetSensorChannelID(std::vector ¶ms, bool testOnly); + void GetSensorChannelID(std::vector ¶ms, bool testOnly); + + void SetRefreshDivider(std::vector ¶ms, bool testOnly); + void GetRefreshDivider(std::vector ¶ms, bool testOnly); + + void RequestStatus(std::vector ¶ms, bool testOnly) override; + void RequestResetSettings(std::vector ¶ms, bool testOnly) override; + + //-------------------------------Utility Functions-------------------------------// + + void RequestCurrentState() override; +}; + +#endif //LLSERVER_ECUI_HOUBOLT_PI_CONTROL_H diff --git a/include/can_houbolt b/include/can_houbolt index cac3fb2f..1e5a2ef2 160000 --- a/include/can_houbolt +++ b/include/can_houbolt @@ -1 +1 @@ -Subproject commit cac3fb2f79a7c608d7d25834baaa7e29e79256a8 +Subproject commit 1e5a2ef28e63694ed6ec2c6c5626a4745c90b262 diff --git a/influxCsvExport/events.csv b/influxCsvExport/events.csv deleted file mode 100644 index e69de29b..00000000 diff --git a/influxCsvExport/main b/influxCsvExport/main deleted file mode 100755 index d81fce6e..00000000 Binary files a/influxCsvExport/main and /dev/null differ diff --git a/install.sh b/install.sh index e09adc7e..33b3045b 100644 --- a/install.sh +++ b/install.sh @@ -2,16 +2,18 @@ cd "$(dirname "$0")" -[ ! -d "./.git/logs" ] && echo "/.git/logs directory doesn't exist! Create it!" && exit 1 +CONFIG_DIR="../config_ecui" -sudo apt install -y cmake - -sudo cp ecui-llserver.service /etc/systemd/system/ -sudo systemctl daemon-reload -sudo systemctl enable ecui-llserver.service -sudo systemctl start ecui-llserver.service -sudo systemctl status ecui-llserver.service - -sudo chmod +x update.sh -bash update.sh +mkdir -p $CONFIG_DIR +#llserver ecui +sudo DOCKER_BUILDKIT=0 docker build \ + -t llserver_ecui -f Dockerfile . +sudo docker run \ + -v $CONFIG_DIR:/home/config_ecui/ \ + --privileged \ + --cap-add=ALL \ + -v /dev:/dev \ + -v /lib/modules:/lib/modules \ + -e "ECUI_CONFIG_PATH=/home/config_ecui" \ + --rm -it --name llserver-ecui llserver_ecui diff --git a/scripts/plot.sh b/scripts/plot.sh deleted file mode 100755 index a2b051d7..00000000 --- a/scripts/plot.sh +++ /dev/null @@ -1,11 +0,0 @@ -#!/bin/bash - -echo "---generating plots...---" -echo $1; -echo $2; - -gnuplot -e "data_path='$1/$2'; img_path='$1/thrust.png'" scripts/thrust_v1.9.plt -gnuplot -e "data_path='$1/$2'; img_path='$1/pressure.png'" scripts/pressure_v1.9.plt -gnuplot -e "data_path='$1/$2'; img_path='$1/temp.png'" scripts/temp_v1.9.plt - -echo "---generating plots done---" diff --git a/scripts/pressure_v1.8.plt b/scripts/pressure_v1.8.plt deleted file mode 100644 index 60271960..00000000 --- a/scripts/pressure_v1.8.plt +++ /dev/null @@ -1,18 +0,0 @@ - - ########### deprecated use v1.9 ############# - -# befehl zum Aufrufen in der comandozeile: -# gnuplot -e "data_path='/home/m/Documents/Datenverarbeitung_fuer_TPH_I_138.066/c++_to_gnuplot/2020_01_23__17_16_32.csv'" -e "img_path='/home/m/Documents/Datenverarbeitung_fuer_TPH_I_138.066/c++_to_gnuplot/daten-Plot.png'" /home/m/Documents/Datenverarbeitung_fuer_TPH_I_138.066/c++_to_gnuplot/gnuplot_v1.8.plt - -set term png size 1500,800 -set output img_path #mit sudo apt-get install gnuplot-x11 geht png - -set grid -set datafile separator ";" - -plot data_path \ -using 1:3 title 'Chamber Pressure in bar' smooth frequency with lines lw 3,\ -'' using 1:5 title 'Fuel Tank Pressure in bar' smooth frequency with lines lw 3,\ -'' using 1:6 title 'Fuel Venturi Pressure in bar' smooth frequency with lines lw 3,\ -'' using 1:9 title 'Oxidizer Tank pressure in bar' smooth frequency with lines lw 3,\ -'' using 1:14 title 'Oxidizer Venturi Pressure in bar' smooth frequency with lines lw 3,\ diff --git a/scripts/pressure_v1.9.plt b/scripts/pressure_v1.9.plt deleted file mode 100644 index 7e80ee15..00000000 --- a/scripts/pressure_v1.9.plt +++ /dev/null @@ -1,16 +0,0 @@ - -# befehl zum Aufrufen in der comandozeile: -# gnuplot -e "data_path='/home/m/Documents/Datenverarbeitung_fuer_TPH_I_138.066/c++_to_gnuplot/2020_01_23__17_16_32.csv'" -e "img_path='/home/m/Documents/Datenverarbeitung_fuer_TPH_I_138.066/c++_to_gnuplot/daten-Plot.png'" /home/m/Documents/Datenverarbeitung_fuer_TPH_I_138.066/c++_to_gnuplot/gnuplot_v1.8.plt - -set term png size 1500,800 -set output img_path #mit sudo apt-get install gnuplot-x11 geht png - -set grid -set datafile separator ";" - -plot data_path \ -using 1:11 title 'Chamber Pressure [bar]' smooth frequency with lines lw 3,\ -'' using 1:5 title 'Fuel Tank Pressure [bar]' smooth frequency with lines lw 3,\ -'' using 1:8 title 'Fuel Venturi Pressure [bar]' smooth frequency with lines lw 3,\ -'' using 1:6 title 'Oxidizer Tank pressure [bar]' smooth frequency with lines lw 3,\ -'' using 1:9 title 'Oxidizer Venturi Pressure [bar]' smooth frequency with lines lw 3,\ diff --git a/scripts/temp_v1.8.plt b/scripts/temp_v1.8.plt deleted file mode 100644 index 917b5369..00000000 --- a/scripts/temp_v1.8.plt +++ /dev/null @@ -1,17 +0,0 @@ - - ########### deprecated use v1.9 ############# - -# befehl zum Aufrufen in der comandozeile: -# gnuplot -e "data_path='/home/m/Documents/Datenverarbeitung_fuer_TPH_I_138.066/c++_to_gnuplot/2020_01_23__17_16_32.csv'" -e "img_path='/home/m/Documents/Datenverarbeitung_fuer_TPH_I_138.066/c++_to_gnuplot/daten-Plot.png'" /home/m/Documents/Datenverarbeitung_fuer_TPH_I_138.066/c++_to_gnuplot/gnuplot_v1.8.plt - -set term png size 1500,800 -set output img_path #mit sudo apt-get install gnuplot-x11 geht png - -set grid -set datafile separator ";" - -plot data_path \ -using 1:10 title 'Oxidizer Tank Bottom Temp in C' smooth frequency with lines lw 3,\ -'' using 1:11 title 'Oxidizer Tank Middle Bottom Temp in C' smooth frequency with lines lw 3,\ -'' using 1:12 title 'Oxidizer Tank Middle Top Temp in C' smooth frequency with lines lw 3,\ -'' using 1:13 title 'Oxidizer Tank Top Temp in C' smooth frequency with lines lw 3,\ diff --git a/scripts/temp_v1.9.plt b/scripts/temp_v1.9.plt deleted file mode 100644 index 4c1858f0..00000000 --- a/scripts/temp_v1.9.plt +++ /dev/null @@ -1,15 +0,0 @@ - -# befehl zum Aufrufen in der comandozeile: -# gnuplot -e "data_path='/home/m/Documents/Datenverarbeitung_fuer_TPH_I_138.066/c++_to_gnuplot/2020_01_23__17_16_32.csv'" -e "img_path='/home/m/Documents/Datenverarbeitung_fuer_TPH_I_138.066/c++_to_gnuplot/daten-Plot.png'" /home/m/Documents/Datenverarbeitung_fuer_TPH_I_138.066/c++_to_gnuplot/gnuplot_v1.8.plt - -set term png size 1500,800 -set output img_path #mit sudo apt-get install gnuplot-x11 geht png - -set grid -set datafile separator ";" - -plot data_path \ -using 1:16 title 'Oxidizer Tank Bottom Temp [C]' smooth frequency with lines lw 3,\ -'' using 1:13 title 'Oxidizer Tank Middle Bottom Temp [C]' smooth frequency with lines lw 3,\ -'' using 1:10 title 'Oxidizer Tank Middle Top Temp [C]' smooth frequency with lines lw 3,\ -'' using 1:7 title 'Oxidizer Tank Top Temp [C]' smooth frequency with lines lw 3,\ diff --git a/scripts/thrust_v1.8.plt b/scripts/thrust_v1.8.plt deleted file mode 100644 index ea7541f3..00000000 --- a/scripts/thrust_v1.8.plt +++ /dev/null @@ -1,24 +0,0 @@ - - ########### deprecated use v1.9 ############# - -# befehl zum Aufrufen in der comandozeile: -# gnuplot -e "data_path='/home/m/Documents/Datenverarbeitung_fuer_TPH_I_138.066/c++_to_gnuplot/2020_01_23__17_16_32.csv'" -e "img_path='/home/m/Documents/Datenverarbeitung_fuer_TPH_I_138.066/c++_to_gnuplot/daten-Plot.png'" /home/m/Documents/Datenverarbeitung_fuer_TPH_I_138.066/c++_to_gnuplot/gnuplot_v1.8.plt - -set term png size 1500,800 -set output img_path #mit sudo apt-get install gnuplot-x11 geht png - -set grid -set datafile separator ";" - - -stats data_path every ::2::500 using 15 name 'averageTrust1' nooutput #durchscnitt von wert 2 bis 500 herausfinden von colum 3 -stats '' every ::2::500 using 16 name 'averageTrust2' nooutput -stats '' every ::0::500 using 17 name 'averageTrust3' nooutput - - -plot data_path \ -using 1:15 title 'Thrust 1 in N' smooth frequency with lines lw 3,\ -'' using 1:16 title 'Thrust 2 in N' smooth frequency with lines lw 3,\ -'' using 1:17 title 'Thrust 3 in N' smooth frequency with lines lw 3,\ -'' using 1:(($15+$16+$17-averageTrust1_mean-averageTrust2_mean-averageTrust3_mean)*8.252e-5) title 'Thrust in N' smooth frequency with lines lw 3,\ -'' using 1:18 title 'Thrust Sum in N' smooth frequency with lines lw 3,\ diff --git a/scripts/thrust_v1.9.plt b/scripts/thrust_v1.9.plt deleted file mode 100644 index 30ba7068..00000000 --- a/scripts/thrust_v1.9.plt +++ /dev/null @@ -1,22 +0,0 @@ - -# befehl zum Aufrufen in der comandozeile: -# gnuplot -e "data_path='/home/m/Documents/Datenverarbeitung_fuer_TPH_I_138.066/c++_to_gnuplot/2020_01_23__17_16_32.csv'" -e "img_path='/home/m/Documents/Datenverarbeitung_fuer_TPH_I_138.066/c++_to_gnuplot/daten-Plot.png'" /home/m/Documents/Datenverarbeitung_fuer_TPH_I_138.066/c++_to_gnuplot/gnuplot_v1.8.plt - -set term png size 1500,800 -set output img_path #mit sudo apt-get install gnuplot-x11 geht png - -set grid -set datafile separator ";" - - -stats data_path every ::2::500 using 18 name 'averageTrust1' nooutput #durchscnitt von wert 2 bis 500 herausfinden von colum 3 -stats '' every ::2::500 using 19 name 'averageTrust2' nooutput -stats '' every ::2::500 using 20 name 'averageTrust3' nooutput - - -plot data_path \ -using 1:18 title 'Thrust 1 [N]' smooth frequency with lines lw 3,\ -'' using 1:19 title 'Thrust 2 [N]' smooth frequency with lines lw 3,\ -'' using 1:20 title 'Thrust 3 [N]' smooth frequency with lines lw 3,\ -'' using 1:(($18+$19+$20-averageTrust1_mean-averageTrust2_mean-averageTrust3_mean)*8.252e-5) title 'Thrust in N' smooth frequency with lines lw 3,\ -'' using 1:20 title 'Thrust Sum in N' smooth frequency with lines lw 3,\ diff --git a/src/LLController.cpp b/src/LLController.cpp index e84dc154..319c0a0a 100644 --- a/src/LLController.cpp +++ b/src/LLController.cpp @@ -18,7 +18,7 @@ void LLController::PrintLogo() { - std::ifstream f("img/stAscii.txt"); + std::ifstream f("img/logo_short.txt"); if (f.is_open()) std::cout << f.rdbuf(); diff --git a/src/SequenceManager.cpp b/src/SequenceManager.cpp index 3acefc01..59ccbcf6 100644 --- a/src/SequenceManager.cpp +++ b/src/SequenceManager.cpp @@ -281,8 +281,9 @@ void SequenceManager::StartSequence(nlohmann::json jsonSeq, nlohmann::json jsonA sequenceRunning = true; sequenceThread = std::thread(&SequenceManager::sequenceLoop, this, interval_us); //sequenceThread.detach(); + std::string sequence_name = jsonSeq["data"][0]["desc"]; - Debug::print("Sequence Started"); + Debug::print("Sequence Started " + sequence_name); } } diff --git a/src/can/CANDriverKvaser.cpp b/src/can/CANDriverKvaser.cpp index 9a415be7..cb32feb7 100644 --- a/src/can/CANDriverKvaser.cpp +++ b/src/can/CANDriverKvaser.cpp @@ -274,7 +274,7 @@ canStatus CANDriverKvaser::InitializeCANChannel(uint32_t canBusChannelID) { return stat; } - Debug::print("can channel bus %d: arb-bitrate %d", canBusChannelID, arbitrationParamsMap[canBusChannelID].bitrate); + Debug::print("can channel bus %d: bitrate %d, arb-bitrate %d", canBusChannelID, dataParamsMap[canBusChannelID].bitrate, arbitrationParamsMap[canBusChannelID].bitrate); stat = canSetBusParams(canHandlesMap[canBusChannelID], arbitrationParamsMap[canBusChannelID].bitrate, arbitrationParamsMap[canBusChannelID].timeSegment1, diff --git a/src/can/CANManager.cpp b/src/can/CANManager.cpp index c3314659..02bad3f6 100644 --- a/src/can/CANManager.cpp +++ b/src/can/CANManager.cpp @@ -195,7 +195,7 @@ CANResult CANManager::Init(Config &config) initialized = true; Debug::print("Request current state and config from nodes...\n"); - RequestCurrentState(); + //RequestCurrentState(); } catch (std::exception& e) @@ -387,7 +387,17 @@ void CANManager::OnCANRecv(uint8_t canBusChannelID, uint32_t canID, uint8_t *pay { if (canIDStruct->info.direction == 0) { - Debug::print("Direction bit master to node from node %d on bus %d, delegating msg...", nodeID, canBusChannelID); + Debug::print("Direction bit master to node %d on bus %d, delegating msg...", nodeID, canBusChannelID); + std::string msg; + msg += "\nNode ID: " + std::to_string(nodeID) + "\n"; + msg += "Channel ID: " + std::to_string(canMsg->bit.info.channel_id) + "\n"; + msg += "CMD ID: " + std::to_string(canMsg->bit.cmd_id) + "\n"; + for (int i = 0; i < payloadLength; i++) + { + msg += std::to_string(canMsg->bit.data.uint8[i]) + " "; + } + msg += "\n"; + Debug::print(msg); //TODO: DIRTY HOTFIX, remove it std::vector channels = {0,1,2,3}; channels.erase(channels.begin()+canBusChannelID); diff --git a/src/can/Control.cpp b/src/can/Control.cpp index 0f07d880..ef626bf3 100644 --- a/src/can/Control.cpp +++ b/src/can/Control.cpp @@ -5,43 +5,42 @@ #include "can/Control.h" const std::vector Control::states = - { - "Enabled", - "Target", - "Threshold", - "Hysteresis", - "ActuatorChannelID", - "SensorChannelID", - "RefreshDivider", - "RequestStatus", - "ResetAllSettings" - }; + { + "Enabled", + "Target", + "Threshold", + "Hysteresis", + "ActuatorChannelID", + "SensorChannelID", + "RefreshDivider", + "RequestStatus", + "ResetAllSettings" + }; const std::map> Control::scalingMap = - { - {"Enabled", {1.0, 0.0}}, - {"Position", {1.0, 0.0}}, - {"Target", {0.003735, 0.0}}, - {"Threshold", {1.0, 0.0}}, - {"Hysteresis", {0.003735, 0.0}}, - {"ActuatorChannelID", {1.0, 0.0}}, - {"SensorChannelID", {1.0, 0.0}}, - {"RefreshDivider", {1.0, 0.0}}, - }; - -const std::map Control::variableMap = - { - {CONTROL_ENABLED, "Enabled"}, - {CONTROL_TARGET, "Target"}, - {CONTROL_THRESHOLD, "Threshold"}, - {CONTROL_HYSTERESIS, "Hysteresis"}, - {CONTROL_ACTUATOR_CHANNEL_ID, "ActuatorChannelID"}, - {CONTROL_SENSOR_CHANNEL_ID, "SensorChannelID"}, - {CONTROL_REFRESH_DIVIDER, "RefreshDivider"}, - }; + { + {"Enabled", {1.0, 0.0}}, + {"Target", {0.001189720812, -15.19667413}}, + {"Threshold", {1.0, 0.0}}, + {"Hysteresis", {0.001189720812, -15.19667413}}, + {"ActuatorChannelID", {1.0, 0.0}}, + {"SensorChannelID", {1.0, 0.0}}, + {"RefreshDivider", {1.0, 0.0}}, + }; + +const std::map Control::variableMap = + { + {CONTROL_ENABLED, "Enabled"}, + {CONTROL_TARGET, "Target"}, + {CONTROL_THRESHOLD, "Threshold"}, + {CONTROL_HYSTERESIS, "Hysteresis"}, + {CONTROL_ACTUATOR_CHANNEL_ID, "ActuatorChannelID"}, + {CONTROL_SENSOR_CHANNEL_ID, "SensorChannelID"}, + {CONTROL_REFRESH_DIVIDER, "RefreshDivider"}, + }; Control::Control(uint8_t channelID, std::string channelName, std::vector sensorScaling, Node *parent) - : Channel("Control", channelID, std::move(channelName), sensorScaling, parent, CONTROL_DATA_N_BYTES), NonNodeChannel(parent) + : Channel("Control", channelID, std::move(channelName), sensorScaling, parent, CONTROL_DATA_N_BYTES), NonNodeChannel(parent) { commandMap = { {"SetEnabled", {std::bind(&Control::SetEnabled, this, std::placeholders::_1, std::placeholders::_2), {"Value"}}}, @@ -87,25 +86,25 @@ void Control::ProcessCANCommand(Can_MessageData_t *canMsg, uint32_t &canMsgLengt { switch (canMsg->bit.cmd_id) { - case CONTROL_RES_GET_VARIABLE: - case CONTROL_RES_SET_VARIABLE: - GetSetVariableResponse(canMsg, canMsgLength, timestamp, variableMap, scalingMap); - break; - case CONTROL_RES_STATUS: - StatusResponse(canMsg, canMsgLength, timestamp); - break; - case CONTROL_RES_RESET_SETTINGS: - ResetSettingsResponse(canMsg, canMsgLength, timestamp); - break; - case CONTROL_REQ_RESET_SETTINGS: - case CONTROL_REQ_STATUS: - case CONTROL_REQ_SET_VARIABLE: - case CONTROL_REQ_GET_VARIABLE: - //TODO: comment out after testing - //throw std::runtime_error("request message type has been received, major fault in protocol"); - break; - default: - throw std::runtime_error("Control specific command with command id not supported: " + std::to_string(canMsg->bit.cmd_id)); + case CONTROL_RES_GET_VARIABLE: + case CONTROL_RES_SET_VARIABLE: + GetSetVariableResponse(canMsg, canMsgLength, timestamp, variableMap, scalingMap); + break; + case CONTROL_RES_STATUS: + StatusResponse(canMsg, canMsgLength, timestamp); + break; + case CONTROL_RES_RESET_SETTINGS: + ResetSettingsResponse(canMsg, canMsgLength, timestamp); + break; + case CONTROL_REQ_RESET_SETTINGS: + case CONTROL_REQ_STATUS: + case CONTROL_REQ_SET_VARIABLE: + case CONTROL_REQ_GET_VARIABLE: + // TODO: comment out after testing + // throw std::runtime_error("request message type has been received, major fault in protocol"); + break; + default: + throw std::runtime_error("Control specific command with command id not supported: " + std::to_string(canMsg->bit.cmd_id)); } } catch (std::exception &e) @@ -341,12 +340,12 @@ void Control::RequestResetSettings(std::vector ¶ms, bool testOnly) void Control::RequestCurrentState() { std::vector params; - - GetEnabled(params, false); - GetTarget(params, false); - GetThreshold(params, false); - GetHysteresis(params, false); - GetActuatorChannelID(params, false); - GetSensorChannelID(params, false); - GetRefreshDivider(params, false); + + GetEnabled(params, false); + GetTarget(params, false); + GetThreshold(params, false); + GetHysteresis(params, false); + GetActuatorChannelID(params, false); + GetSensorChannelID(params, false); + GetRefreshDivider(params, false); } \ No newline at end of file diff --git a/src/can/Node.cpp b/src/can/Node.cpp index 15bf9cc2..88990cce 100644 --- a/src/can/Node.cpp +++ b/src/can/Node.cpp @@ -14,6 +14,7 @@ #include "can/Servo.h" #include "can/PneumaticValve.h" #include "can/Control.h" +#include "can/PIControl.h" #include "can/IMU.h" #include "can/Rocket.h" #include "StateController.h" @@ -188,6 +189,9 @@ void Node::InitChannels(NodeInfoMsg_t &nodeInfo, std::map(channelInfo[channelID]), std::get<1>(channelInfo[channelID]), this); break; + case CHANNEL_TYPE_PI_CONTROL: + ch = new PIControl(channelID, std::get<0>(channelInfo[channelID]), std::get<1>(channelInfo[channelID]), this); + break; case CHANNEL_TYPE_IMU: ch = new IMU(channelID, std::get<0>(channelInfo[channelID]), std::get<1>(channelInfo[channelID]), this); break; diff --git a/src/can/PIControl.cpp b/src/can/PIControl.cpp new file mode 100644 index 00000000..760eca70 --- /dev/null +++ b/src/can/PIControl.cpp @@ -0,0 +1,521 @@ +// +// Created by Markus on 03.09.21. +// + +#include "can/PIControl.h" + +const std::vector PIControl::states = + { + "Enabled", + "Target", + "P_POS", + "I_POS", + "P_NEG", + "I_NEG", + "SensorSlope", + "SensorOffset", + "OperatingPoint", + "ActuatorChannelID", + "SensorChannelID", + "RefreshDivider", + "RequestStatus", + "ResetAllSettings" + }; + +const std::map> PIControl::scalingMap = + { + {"Enabled", {1.0, 0.0}}, + {"Target", {0.001, 0.0}}, + {"P_POS", {0.001, 0.0}}, + {"I_POS", {0.001, 0.0}}, + {"P_NEG", {0.001, 0.0}}, + {"I_NEG", {0.001, 0.0}}, + {"SensorSlope", {0.001, 0.0}}, + {"SensorOffset", {0.001, 0.0}}, + {"OperatingPoint", {0.001, 0.0}}, + {"ActuatorChannelID", {1.0, 0.0}}, + {"SensorChannelID", {1.0, 0.0}}, + {"RefreshDivider", {1.0, 0.0}}, + }; + +const std::map PIControl::variableMap = + { + {PI_CONTROL_ENABLED, "Enabled"}, + {PI_CONTROL_TARGET, "Target"}, + {PI_CONTROL_P_POS, "P_POS"}, + {PI_CONTROL_I_POS, "I_POS"}, + {PI_CONTROL_P_NEG, "P_NEG"}, + {PI_CONTROL_I_NEG, "I_NEG"}, + {PI_CONTROL_SENSOR_SLOPE, "SensorSlope"}, + {PI_CONTROL_SENSOR_OFFSET, "SensorOffset"}, + {PI_CONTROL_OPERATING_POINT, "OperatingPoint"}, + {PI_CONTROL_ACTUATOR_CHANNEL_ID, "ActuatorChannelID"}, + {PI_CONTROL_SENSOR_CHANNEL_ID, "SensorChannelID"}, + {PI_CONTROL_REFRESH_DIVIDER, "RefreshDivider"}, + }; + +PIControl::PIControl(uint8_t channelID, std::string channelName, std::vector sensorScaling, Node *parent) + : Channel("PIControl", channelID, std::move(channelName), sensorScaling, parent, PI_CONTROL_DATA_N_BYTES), NonNodeChannel(parent) +{ + commandMap = { + {"SetEnabled", {std::bind(&PIControl::SetEnabled, this, std::placeholders::_1, std::placeholders::_2), {"Value"}}}, + {"GetEnabled", {std::bind(&PIControl::GetEnabled, this, std::placeholders::_1, std::placeholders::_2), {}}}, + {"SetTarget", {std::bind(&PIControl::SetTarget, this, std::placeholders::_1, std::placeholders::_2), {"Value"}}}, + {"GetTarget", {std::bind(&PIControl::GetTarget, this, std::placeholders::_1, std::placeholders::_2), {}}}, + {"SetP_POS", {std::bind(&PIControl::SetP_POS, this, std::placeholders::_1, std::placeholders::_2), {"Value"}}}, + {"GetP_POS", {std::bind(&PIControl::GetP_POS, this, std::placeholders::_1, std::placeholders::_2), {}}}, + {"SetI_POS", {std::bind(&PIControl::SetI_POS, this, std::placeholders::_1, std::placeholders::_2), {"Value"}}}, + {"GetI_POS", {std::bind(&PIControl::GetI_POS, this, std::placeholders::_1, std::placeholders::_2), {}}}, + {"SetP_NEG", {std::bind(&PIControl::SetP_NEG, this, std::placeholders::_1, std::placeholders::_2), {"Value"}}}, + {"GetP_NEG", {std::bind(&PIControl::GetP_NEG, this, std::placeholders::_1, std::placeholders::_2), {}}}, + {"SetI_NEG", {std::bind(&PIControl::SetI_NEG, this, std::placeholders::_1, std::placeholders::_2), {"Value"}}}, + {"GetI_NEG", {std::bind(&PIControl::GetI_NEG, this, std::placeholders::_1, std::placeholders::_2), {}}}, + {"SetSensorSlope", {std::bind(&PIControl::SetSensorSlope, this, std::placeholders::_1, std::placeholders::_2), {"Value"}}}, + {"GetSensorSlope", {std::bind(&PIControl::GetSensorSlope, this, std::placeholders::_1, std::placeholders::_2), {}}}, + {"SetSensorOffset", {std::bind(&PIControl::SetSensorOffset, this, std::placeholders::_1, std::placeholders::_2), {"Value"}}}, + {"GetSensorOffset", {std::bind(&PIControl::GetSensorOffset, this, std::placeholders::_1, std::placeholders::_2), {}}}, + {"SetOperatingPoint", {std::bind(&PIControl::SetOperatingPoint, this, std::placeholders::_1, std::placeholders::_2), {"Value"}}}, + {"GetOperatingPoint", {std::bind(&PIControl::GetOperatingPoint, this, std::placeholders::_1, std::placeholders::_2), {}}}, + {"SetActuatorChannelID", {std::bind(&PIControl::SetActuatorChannelID, this, std::placeholders::_1, std::placeholders::_2), {"Value"}}}, + {"GetActuatorChannelID", {std::bind(&PIControl::GetActuatorChannelID, this, std::placeholders::_1, std::placeholders::_2), {}}}, + {"SetSensorChannelID", {std::bind(&PIControl::SetSensorChannelID, this, std::placeholders::_1, std::placeholders::_2), {"Value"}}}, + {"GetSensorChannelID", {std::bind(&PIControl::GetSensorChannelID, this, std::placeholders::_1, std::placeholders::_2), {}}}, + {"SetRefreshDivider", {std::bind(&PIControl::SetRefreshDivider, this, std::placeholders::_1, std::placeholders::_2), {"Value"}}}, + {"GetRefreshDivider", {std::bind(&PIControl::GetRefreshDivider, this, std::placeholders::_1, std::placeholders::_2), {}}}, + {"RequestStatus", {std::bind(&PIControl::RequestStatus, this, std::placeholders::_1, std::placeholders::_2), {}}}, + {"RequestResetSettings", {std::bind(&PIControl::RequestResetSettings, this, std::placeholders::_1, std::placeholders::_2), {}}}, + }; +} + +//---------------------------------------------------------------------------------------// +//-------------------------------GETTER & SETTER Functions-------------------------------// +//---------------------------------------------------------------------------------------// + +std::vector PIControl::GetStates() +{ + std::vector states = PIControl::states; + for (auto &state : states) + { + state = GetStatePrefix() + state; + } + return states; +} + +//-------------------------------------------------------------------------------// +//-------------------------------RECEIVE Functions-------------------------------// +//-------------------------------------------------------------------------------// + +void PIControl::ProcessCANCommand(Can_MessageData_t *canMsg, uint32_t &canMsgLength, uint64_t ×tamp) +{ + try + { + switch (canMsg->bit.cmd_id) + { + case PI_CONTROL_RES_GET_VARIABLE: + case PI_CONTROL_RES_SET_VARIABLE: + GetSetVariableResponse(canMsg, canMsgLength, timestamp, variableMap, scalingMap); + break; + case PI_CONTROL_RES_STATUS: + StatusResponse(canMsg, canMsgLength, timestamp); + break; + case PI_CONTROL_RES_RESET_SETTINGS: + ResetSettingsResponse(canMsg, canMsgLength, timestamp); + break; + case PI_CONTROL_REQ_RESET_SETTINGS: + case PI_CONTROL_REQ_STATUS: + case PI_CONTROL_REQ_SET_VARIABLE: + case PI_CONTROL_REQ_GET_VARIABLE: + // TODO: comment out after testing + // throw std::runtime_error("request message type has been received, major fault in protocol"); + break; + default: + throw std::runtime_error("PIControl specific command with command id not supported: " + std::to_string(canMsg->bit.cmd_id)); + } + } + catch (std::exception &e) + { + throw std::runtime_error("PIControl '" + this->channelName + "' - ProcessCANCommand: " + std::string(e.what())); + } +} + +//----------------------------------------------------------------------------// +//-------------------------------SEND Functions-------------------------------// +//----------------------------------------------------------------------------// + +void PIControl::SetEnabled(std::vector ¶ms, bool testOnly) +{ + std::vector scalingParams = scalingMap.at("Enabled"); + + try + { + SetVariable(PI_CONTROL_REQ_SET_VARIABLE, parent->GetNodeID(), PI_CONTROL_ENABLED, + scalingParams, params, parent->GetCANBusChannelID(), parent->GetCANDriver(), testOnly); + } + catch (std::exception &e) + { + throw std::runtime_error("PIControl - SetEnabled: " + std::string(e.what())); + } +} + +void PIControl::GetEnabled(std::vector ¶ms, bool testOnly) +{ + try + { + GetVariable(PI_CONTROL_REQ_GET_VARIABLE, parent->GetNodeID(), PI_CONTROL_ENABLED, + params, parent->GetCANBusChannelID(), parent->GetCANDriver(), testOnly); + } + catch (std::exception &e) + { + throw std::runtime_error("PIControl - GetEnabled: " + std::string(e.what())); + } +} + +void PIControl::SetTarget(std::vector ¶ms, bool testOnly) +{ + std::vector scalingParams = scalingMap.at("Target"); + + try + { + SetVariable(PI_CONTROL_REQ_SET_VARIABLE, parent->GetNodeID(), PI_CONTROL_TARGET, + scalingParams, params, parent->GetCANBusChannelID(), parent->GetCANDriver(), testOnly); + } + catch (std::exception &e) + { + throw std::runtime_error("PIControl - SetTarget: " + std::string(e.what())); + } +} + +void PIControl::GetTarget(std::vector ¶ms, bool testOnly) +{ + try + { + GetVariable(PI_CONTROL_REQ_GET_VARIABLE, parent->GetNodeID(), PI_CONTROL_TARGET, + params, parent->GetCANBusChannelID(), parent->GetCANDriver(), testOnly); + } + catch (std::exception &e) + { + throw std::runtime_error("PIControl - GetTarget: " + std::string(e.what())); + } +} + +void PIControl::SetP_POS(std::vector ¶ms, bool testOnly) +{ + std::vector scalingParams = scalingMap.at("P_POS"); + + try + { + SetVariable(PI_CONTROL_REQ_SET_VARIABLE, parent->GetNodeID(), PI_CONTROL_P_POS, + scalingParams, params, parent->GetCANBusChannelID(), parent->GetCANDriver(), testOnly); + } + catch (std::exception &e) + { + throw std::runtime_error("PIControl - SetP_POS: " + std::string(e.what())); + } +} + +void PIControl::GetP_POS(std::vector ¶ms, bool testOnly) +{ + try + { + GetVariable(PI_CONTROL_REQ_GET_VARIABLE, parent->GetNodeID(), PI_CONTROL_P_POS, + params, parent->GetCANBusChannelID(), parent->GetCANDriver(), testOnly); + } + catch (std::exception &e) + { + throw std::runtime_error("PIControl - GetP_POS: " + std::string(e.what())); + } +} + +void PIControl::SetI_POS(std::vector ¶ms, bool testOnly) +{ + std::vector scalingParams = scalingMap.at("I_POS"); + + try + { + SetVariable(PI_CONTROL_REQ_SET_VARIABLE, parent->GetNodeID(), PI_CONTROL_I_POS, + scalingParams, params, parent->GetCANBusChannelID(), parent->GetCANDriver(), testOnly); + } + catch (std::exception &e) + { + throw std::runtime_error("PIControl - SetI_POS: " + std::string(e.what())); + } +} + +void PIControl::GetI_POS(std::vector ¶ms, bool testOnly) +{ + try + { + GetVariable(PI_CONTROL_REQ_GET_VARIABLE, parent->GetNodeID(), PI_CONTROL_I_POS, + params, parent->GetCANBusChannelID(), parent->GetCANDriver(), testOnly); + } + catch (std::exception &e) + { + throw std::runtime_error("PIControl - GetI_POS: " + std::string(e.what())); + } +} + +void PIControl::SetP_NEG(std::vector ¶ms, bool testOnly) +{ + std::vector scalingParams = scalingMap.at("P_NEG"); + + try + { + SetVariable(PI_CONTROL_REQ_SET_VARIABLE, parent->GetNodeID(), PI_CONTROL_P_NEG, + scalingParams, params, parent->GetCANBusChannelID(), parent->GetCANDriver(), testOnly); + } + catch (std::exception &e) + { + throw std::runtime_error("PIControl - SetP_NEG: " + std::string(e.what())); + } +} + +void PIControl::GetP_NEG(std::vector ¶ms, bool testOnly) +{ + try + { + GetVariable(PI_CONTROL_REQ_GET_VARIABLE, parent->GetNodeID(), PI_CONTROL_P_NEG, + params, parent->GetCANBusChannelID(), parent->GetCANDriver(), testOnly); + } + catch (std::exception &e) + { + throw std::runtime_error("PIControl - GetP_NEG: " + std::string(e.what())); + } +} + +void PIControl::SetI_NEG(std::vector ¶ms, bool testOnly) +{ + std::vector scalingParams = scalingMap.at("I_NEG"); + + try + { + SetVariable(PI_CONTROL_REQ_SET_VARIABLE, parent->GetNodeID(), PI_CONTROL_I_NEG, + scalingParams, params, parent->GetCANBusChannelID(), parent->GetCANDriver(), testOnly); + } + catch (std::exception &e) + { + throw std::runtime_error("PIControl - SetI_NEG: " + std::string(e.what())); + } +} + +void PIControl::GetI_NEG(std::vector ¶ms, bool testOnly) +{ + try + { + GetVariable(PI_CONTROL_REQ_GET_VARIABLE, parent->GetNodeID(), PI_CONTROL_I_NEG, + params, parent->GetCANBusChannelID(), parent->GetCANDriver(), testOnly); + } + catch (std::exception &e) + { + throw std::runtime_error("PIControl - GetI_NEG: " + std::string(e.what())); + } +} + +void PIControl::SetSensorSlope(std::vector ¶ms, bool testOnly) +{ + std::vector scalingParams = scalingMap.at("SensorSlope"); + + try + { + SetVariable(PI_CONTROL_REQ_SET_VARIABLE, parent->GetNodeID(), PI_CONTROL_SENSOR_SLOPE, + scalingParams, params, parent->GetCANBusChannelID(), parent->GetCANDriver(), testOnly); + } + catch (std::exception &e) + { + throw std::runtime_error("PIControl - SetSensorSlope: " + std::string(e.what())); + } +} + +void PIControl::GetSensorSlope(std::vector ¶ms, bool testOnly) +{ + try + { + GetVariable(PI_CONTROL_REQ_GET_VARIABLE, parent->GetNodeID(), PI_CONTROL_SENSOR_SLOPE, + params, parent->GetCANBusChannelID(), parent->GetCANDriver(), testOnly); + } + catch (std::exception &e) + { + throw std::runtime_error("PIControl - GetSensorSlope: " + std::string(e.what())); + } +} + +void PIControl::SetSensorOffset(std::vector ¶ms, bool testOnly) +{ + std::vector scalingParams = scalingMap.at("SensorOffset"); + + try + { + SetVariable(PI_CONTROL_REQ_SET_VARIABLE, parent->GetNodeID(), PI_CONTROL_SENSOR_OFFSET, + scalingParams, params, parent->GetCANBusChannelID(), parent->GetCANDriver(), testOnly); + } + catch (std::exception &e) + { + throw std::runtime_error("PIControl - SetSensorOffset: " + std::string(e.what())); + } +} + +void PIControl::GetSensorOffset(std::vector ¶ms, bool testOnly) +{ + try + { + GetVariable(PI_CONTROL_REQ_GET_VARIABLE, parent->GetNodeID(), PI_CONTROL_SENSOR_OFFSET, + params, parent->GetCANBusChannelID(), parent->GetCANDriver(), testOnly); + } + catch (std::exception &e) + { + throw std::runtime_error("PIControl - GetSensorOffset: " + std::string(e.what())); + } +} + +void PIControl::SetOperatingPoint(std::vector ¶ms, bool testOnly) +{ + std::vector scalingParams = scalingMap.at("OperatingPoint"); + + try + { + SetVariable(PI_CONTROL_REQ_SET_VARIABLE, parent->GetNodeID(), PI_CONTROL_OPERATING_POINT, + scalingParams, params, parent->GetCANBusChannelID(), parent->GetCANDriver(), testOnly); + } + catch (std::exception &e) + { + throw std::runtime_error("PIControl - SetOperatingPoint: " + std::string(e.what())); + } +} + +void PIControl::GetOperatingPoint(std::vector ¶ms, bool testOnly) +{ + try + { + GetVariable(PI_CONTROL_REQ_GET_VARIABLE, parent->GetNodeID(), PI_CONTROL_OPERATING_POINT, + params, parent->GetCANBusChannelID(), parent->GetCANDriver(), testOnly); + } + catch (std::exception &e) + { + throw std::runtime_error("PIControl - GetOperatingPoint: " + std::string(e.what())); + } +} + +void PIControl::SetActuatorChannelID(std::vector ¶ms, bool testOnly) +{ + std::vector scalingParams = scalingMap.at("ActuatorChannelID"); + + try + { + SetVariable(PI_CONTROL_REQ_SET_VARIABLE, parent->GetNodeID(), PI_CONTROL_ACTUATOR_CHANNEL_ID, + scalingParams, params, parent->GetCANBusChannelID(), parent->GetCANDriver(), testOnly); + } + catch (std::exception &e) + { + throw std::runtime_error("PIControl - SetActuatorChannelID: " + std::string(e.what())); + } +} + +void PIControl::GetActuatorChannelID(std::vector ¶ms, bool testOnly) +{ + try + { + GetVariable(PI_CONTROL_REQ_GET_VARIABLE, parent->GetNodeID(), PI_CONTROL_ACTUATOR_CHANNEL_ID, + params, parent->GetCANBusChannelID(), parent->GetCANDriver(), testOnly); + } + catch (std::exception &e) + { + throw std::runtime_error("PIControl - GetActuatorChannelID: " + std::string(e.what())); + } +} + +void PIControl::SetSensorChannelID(std::vector ¶ms, bool testOnly) +{ + std::vector scalingParams = scalingMap.at("SensorChannelID"); + + try + { + SetVariable(PI_CONTROL_REQ_SET_VARIABLE, parent->GetNodeID(), PI_CONTROL_SENSOR_CHANNEL_ID, + scalingParams, params, parent->GetCANBusChannelID(), parent->GetCANDriver(), testOnly); + } + catch (std::exception &e) + { + throw std::runtime_error("PIControl - SetSensorChannelID: " + std::string(e.what())); + } +} + +void PIControl::GetSensorChannelID(std::vector ¶ms, bool testOnly) +{ + try + { + GetVariable(PI_CONTROL_REQ_GET_VARIABLE, parent->GetNodeID(), PI_CONTROL_SENSOR_CHANNEL_ID, + params, parent->GetCANBusChannelID(), parent->GetCANDriver(), testOnly); + } + catch (std::exception &e) + { + throw std::runtime_error("PIControl - GetSensorChannelID: " + std::string(e.what())); + } +} + +void PIControl::SetRefreshDivider(std::vector ¶ms, bool testOnly) +{ + std::vector scalingParams = scalingMap.at("RefreshDivider"); + + try + { + SetVariable(PI_CONTROL_REQ_SET_VARIABLE, parent->GetNodeID(), PI_CONTROL_REFRESH_DIVIDER, + scalingParams, params, parent->GetCANBusChannelID(), parent->GetCANDriver(), testOnly); + } + catch (std::exception &e) + { + throw std::runtime_error("PIControl - SetRefreshDivider: " + std::string(e.what())); + } +} + +void PIControl::GetRefreshDivider(std::vector ¶ms, bool testOnly) +{ + try + { + GetVariable(PI_CONTROL_REQ_GET_VARIABLE, parent->GetNodeID(), PI_CONTROL_REFRESH_DIVIDER, + params, parent->GetCANBusChannelID(), parent->GetCANDriver(), testOnly); + } + catch (std::exception &e) + { + throw std::runtime_error("PIControl - GetRefreshDivider: " + std::string(e.what())); + } +} + +void PIControl::RequestStatus(std::vector ¶ms, bool testOnly) +{ + try + { + SendNoPayloadCommand(params, parent->GetNodeID(), PI_CONTROL_REQ_STATUS, parent->GetCANBusChannelID(), parent->GetCANDriver(), testOnly); + } + catch (std::exception &e) + { + throw std::runtime_error("PIControl - RequestStatus: " + std::string(e.what())); + } +} + +void PIControl::RequestResetSettings(std::vector ¶ms, bool testOnly) +{ + try + { + SendNoPayloadCommand(params, parent->GetNodeID(), PI_CONTROL_REQ_RESET_SETTINGS, parent->GetCANBusChannelID(), parent->GetCANDriver(), testOnly); + } + catch (std::exception &e) + { + throw std::runtime_error("PIControl - RequestResetSettings: " + std::string(e.what())); + } +} + +void PIControl::RequestCurrentState() +{ + std::vector params; + + GetEnabled(params, false); + GetTarget(params, false); + GetP_POS(params, false); + GetI_POS(params, false); + GetP_NEG(params, false); + GetI_NEG(params, false); + GetSensorSlope(params, false); + GetSensorOffset(params, false); + GetOperatingPoint(params, false); + GetActuatorChannelID(params, false); + GetSensorChannelID(params, false); + GetRefreshDivider(params, false); +} \ No newline at end of file diff --git a/src/can/Servo.cpp b/src/can/Servo.cpp index c9d500fa..c78173ca 100644 --- a/src/can/Servo.cpp +++ b/src/can/Servo.cpp @@ -5,68 +5,67 @@ #include "can/Servo.h" const std::vector Servo::states = - { - "Position", - "TargetPosition", - "TargetPressure", - "MaxSpeed", - "MaxAccel", - "MaxTorque", - "P", - "I", - "D", - "SensorChannelID", - "Startpoint", - "Endpoint", - "PWMEnabled", - "PositionRaw", - "RefreshDivider", - "RequestStatus", - "ResetAllSettings" - }; + { + "Position", + "TargetPosition", + "TargetPressure", + "MaxSpeed", + "MaxAccel", + "MaxTorque", + "P", + "I", + "D", + "SensorChannelID", + "Startpoint", + "Endpoint", + "PWMEnabled", + "PositionRaw", + "RefreshDivider", + "RequestStatus", + "ResetAllSettings"}; const std::map> Servo::scalingMap = - { - {"Position", {1.0, 0.0}}, - {"TargetPosition", {1.0, 0.0}}, - {"TargetPressure", {1.0, 0.0}}, - {"MaxSpeed", {1.0, 0.0}}, - {"MaxAccel", {1.0, 0.0}}, - {"MaxTorque", {1.0, 0.0}}, - {"P", {1.0, 0.0}}, - {"I", {1.0, 0.0}}, - {"D", {1.0, 0.0}}, - {"SensorChannelID", {1.0, 0.0}}, - {"Startpoint", {1.0, 0.0}}, - {"Endpoint", {1.0, 0.0}}, - {"PWMEnabled", {1.0, 0.0}}, - {"PositionRaw", {1.0, 0.0}}, - {"MovePosition", {1.0, 0.0}}, - {"MoveInterval", {1.0, 0.0}}, - {"RefreshDivider", {1.0, 0.0}}, - }; - -const std::map Servo::variableMap = - { - {SERVO_POSITION, "Position"}, - {SERVO_TARGET_POSITION, "TargetPosition"}, - {SERVO_TARGET_PRESSURE, "TargetPressure"}, - {SERVO_MAX_SPEED, "MaxSpeed"}, - {SERVO_MAX_ACCEL, "MaxAccel"}, - {SERVO_MAX_TORQUE, "MaxTorque"}, - {SERVO_P_PARAM, "P"}, - {SERVO_I_PARAM, "I"}, - {SERVO_D_PARAM, "D"}, - {SERVO_SENSOR_CHANNEL_ID, "SensorChannelID"}, - {SERVO_POSITION_STARTPOINT, "Startpoint"}, - {SERVO_POSITION_ENDPOINT, "Endpoint"}, - {SERVO_PWM_ENABLED, "PWMEnabled"}, - {SERVO_POSITION_RAW, "PositionRaw"}, - {SERVO_SENSOR_REFRESH_DIVIDER, "RefreshDivider"}, - }; + { + {"Position", {0.00152590219, 0.0}}, + {"TargetPosition", {0.00152590219, 0.0}}, + {"TargetPressure", {1.0, 0.0}}, + {"MaxSpeed", {1.0, 0.0}}, + {"MaxAccel", {1.0, 0.0}}, + {"MaxTorque", {1.0, 0.0}}, + {"P", {1.0, 0.0}}, + {"I", {1.0, 0.0}}, + {"D", {1.0, 0.0}}, + {"SensorChannelID", {1.0, 0.0}}, + {"Startpoint", {1.0, 0.0}}, + {"Endpoint", {1.0, 0.0}}, + {"PWMEnabled", {1.0, 0.0}}, + {"PositionRaw", {1.0, 0.0}}, + {"MovePosition", {1.0, 0.0}}, + {"MoveInterval", {1.0, 0.0}}, + {"RefreshDivider", {1.0, 0.0}}, +}; + +const std::map Servo::variableMap = + { + {SERVO_POSITION, "Position"}, + {SERVO_TARGET_POSITION, "TargetPosition"}, + {SERVO_TARGET_PRESSURE, "TargetPressure"}, + {SERVO_MAX_SPEED, "MaxSpeed"}, + {SERVO_MAX_ACCEL, "MaxAccel"}, + {SERVO_MAX_TORQUE, "MaxTorque"}, + {SERVO_P_PARAM, "P"}, + {SERVO_I_PARAM, "I"}, + {SERVO_D_PARAM, "D"}, + {SERVO_SENSOR_CHANNEL_ID, "SensorChannelID"}, + {SERVO_POSITION_STARTPOINT, "Startpoint"}, + {SERVO_POSITION_ENDPOINT, "Endpoint"}, + {SERVO_PWM_ENABLED, "PWMEnabled"}, + {SERVO_POSITION_RAW, "PositionRaw"}, + {SERVO_SENSOR_REFRESH_DIVIDER, "RefreshDivider"}, +}; Servo::Servo(uint8_t channelID, std::string channelName, std::vector sensorScaling, Node *parent) - : Channel("Servo", channelID, std::move(channelName), sensorScaling, parent, SERVO_DATA_N_BYTES), NonNodeChannel(parent) + : Channel("Servo", channelID, std::move(channelName), sensorScaling, parent, SERVO_DATA_N_BYTES), NonNodeChannel(parent) { commandMap = { {"SetPosition", {std::bind(&Servo::SetPosition, this, std::placeholders::_1, std::placeholders::_2), {"Value"}}}, @@ -101,7 +100,7 @@ Servo::Servo(uint8_t channelID, std::string channelName, std::vector sen {"GetRefreshDivider", {std::bind(&Servo::GetRefreshDivider, this, std::placeholders::_1, std::placeholders::_2), {}}}, {"RequestStatus", {std::bind(&Servo::RequestStatus, this, std::placeholders::_1, std::placeholders::_2), {}}}, {"RequestResetSettings", {std::bind(&Servo::RequestResetSettings, this, std::placeholders::_1, std::placeholders::_2), {}}}, - {"RequestMove", {std::bind(&Servo::RequestMove, this, std::placeholders::_1, std::placeholders::_2),{"Position","TimeInterval"}}}, + {"RequestMove", {std::bind(&Servo::RequestMove, this, std::placeholders::_1, std::placeholders::_2), {"Position", "TimeInterval"}}}, }; } @@ -129,25 +128,25 @@ void Servo::ProcessCANCommand(Can_MessageData_t *canMsg, uint32_t &canMsgLength, { switch (canMsg->bit.cmd_id) { - case SERVO_RES_GET_VARIABLE: - case SERVO_RES_SET_VARIABLE: - GetSetVariableResponse(canMsg, canMsgLength, timestamp, variableMap, scalingMap); - break; - case SERVO_RES_STATUS: - StatusResponse(canMsg, canMsgLength, timestamp); - break; - case SERVO_RES_RESET_SETTINGS: - ResetSettingsResponse(canMsg, canMsgLength, timestamp); - break; - case SERVO_REQ_RESET_SETTINGS: - case SERVO_REQ_STATUS: - case SERVO_REQ_SET_VARIABLE: - case SERVO_REQ_GET_VARIABLE: - //TODO: comment out after testing - //throw std::runtime_error("request message type has been received, major fault in protocol"); - break; - default: - throw std::runtime_error("Servo specific command with command id not supported: " + std::to_string(canMsg->bit.cmd_id)); + case SERVO_RES_GET_VARIABLE: + case SERVO_RES_SET_VARIABLE: + GetSetVariableResponse(canMsg, canMsgLength, timestamp, variableMap, scalingMap); + break; + case SERVO_RES_STATUS: + StatusResponse(canMsg, canMsgLength, timestamp); + break; + case SERVO_RES_RESET_SETTINGS: + ResetSettingsResponse(canMsg, canMsgLength, timestamp); + break; + case SERVO_REQ_RESET_SETTINGS: + case SERVO_REQ_STATUS: + case SERVO_REQ_SET_VARIABLE: + case SERVO_REQ_GET_VARIABLE: + // TODO: comment out after testing + // throw std::runtime_error("request message type has been received, major fault in protocol"); + break; + default: + throw std::runtime_error("Servo specific command with command id not supported: " + std::to_string(canMsg->bit.cmd_id)); } } catch (std::exception &e) @@ -272,7 +271,6 @@ void Servo::GetTargetPressure(std::vector ¶ms, bool testOnly) } } - void Servo::SetMaxSpeed(std::vector ¶ms, bool testOnly) { std::vector scalingParams = scalingMap.at("MaxSpeed"); @@ -585,7 +583,7 @@ void Servo::RequestMove(std::vector ¶ms, bool testOnly) { try { - if (params.size() != 2) //number of required parameters + if (params.size() != 2) // number of required parameters { throw std::runtime_error("2 parameters expected, but " + std::to_string(params.size()) + " were provided"); } @@ -593,10 +591,10 @@ void Servo::RequestMove(std::vector ¶ms, bool testOnly) std::vector scalingInterval = scalingMap.at("MoveInterval"); ServoMoveMsg_t moveMsg = {0}; - moveMsg.position = Channel::ScaleAndConvertInt32(params[0],scalingPosition[0],scalingPosition[1]); - moveMsg.interval = Channel::ScaleAndConvertInt32(params[1],scalingInterval[0],scalingInterval[1]); + moveMsg.position = Channel::ScaleAndConvertInt32(params[0], scalingPosition[0], scalingPosition[1]); + moveMsg.interval = Channel::ScaleAndConvertInt32(params[1], scalingInterval[0], scalingInterval[1]); - SendStandardCommand(parent->GetNodeID(), SERVO_REQ_MOVE, (uint8_t *) &moveMsg, sizeof(moveMsg), parent->GetCANBusChannelID(), parent->GetCANDriver(), testOnly); + SendStandardCommand(parent->GetNodeID(), SERVO_REQ_MOVE, (uint8_t *)&moveMsg, sizeof(moveMsg), parent->GetCANBusChannelID(), parent->GetCANDriver(), testOnly); } catch (std::exception &e) { @@ -632,19 +630,19 @@ void Servo::RequestCurrentState() { std::vector params; - GetPosition(params, false); + GetPosition(params, false); GetPositionRaw(params, false); - GetTargetPosition(params, false); - GetTargetPressure(params, false); - GetMaxSpeed(params, false); - GetMaxAccel(params, false); - GetMaxTorque(params, false); - GetP(params, false); - GetI(params, false); - GetD(params, false); - GetSensorChannelID(params, false); - GetStartpoint(params, false); - GetEndpoint(params, false); - GetPWMEnabled(params, false); - GetRefreshDivider(params, false); + GetTargetPosition(params, false); + GetTargetPressure(params, false); + GetMaxSpeed(params, false); + GetMaxAccel(params, false); + GetMaxTorque(params, false); + GetP(params, false); + GetI(params, false); + GetD(params, false); + GetSensorChannelID(params, false); + GetStartpoint(params, false); + GetEndpoint(params, false); + GetPWMEnabled(params, false); + GetRefreshDivider(params, false); } \ No newline at end of file diff --git a/src/drivers/PythonController.cpp b/src/drivers/PythonController.cpp index 011e0123..a2b6954a 100644 --- a/src/drivers/PythonController.cpp +++ b/src/drivers/PythonController.cpp @@ -8,9 +8,9 @@ #include #include -static std::string PythonController::pyEnv = ""; +std::string PythonController::pyEnv = ""; -static void PythonController::SetPythonEnvironment(std::string pyEnv) { +void PythonController::SetPythonEnvironment(std::string pyEnv) { PythonController::pyEnv = pyEnv; } @@ -230,7 +230,8 @@ void PythonController::RunPyScript(std::string scriptPath) { PythonController::SetupImports(); - FILE *fp = _Py_fopen(scriptPath.c_str(), "r"); + std::wstring path = std::wstring(scriptPath.begin(), scriptPath.end()); + FILE *fp = _Py_wfopen(path.c_str(), L"r"); StateController::Instance() -> SetState((std::string) "python_running", 1, utils::getCurrentTimestamp()); @@ -270,7 +271,8 @@ void PythonController::RunPyScriptWithArgvWChar(std::string scriptPath, int pyAr PySys_SetArgv(pyArgc, pyArgv); - FILE *fp = _Py_fopen(scriptPath.c_str(), "r"); + std::wstring path = std::wstring(scriptPath.begin(), scriptPath.end()); + FILE *fp = _Py_wfopen(path.c_str(), L"r"); StateController::Instance() -> SetState((std::string) "python_running", 1, utils::getCurrentTimestamp()); diff --git a/update.sh b/update.sh index 887bbc5e..d525f4f7 100755 --- a/update.sh +++ b/update.sh @@ -4,8 +4,4 @@ cd "$(dirname "$0")" git pull -cmake . -DCMAKE_BUILD_TYPE:STRING=Debug -DNO_CANLIB:BOOL=True -DNO_PYTHON:BOOL=True - -make -j3 - -sudo systemctl restart ecui-llserver.service +exec ./install.sh