From c9a7bee3b1617defda61728f8de728445961a29f Mon Sep 17 00:00:00 2001 From: Geoffrey Frogeye Date: Sun, 6 May 2018 18:34:56 +0200 Subject: [PATCH] Added simulation --- raspberrypi/Makefile | 1 + simu/.gitignore | 2 + simu/mat2h.py | 68 ++++++++ simu/mat2h.sh | 15 ++ simu/modelisation.slx | Bin 0 -> 32512 bytes simu/simu.m | 373 ++++++++++++++++++++++++++++++++++++++++++ 6 files changed, 459 insertions(+) create mode 100644 simu/.gitignore create mode 100755 simu/mat2h.py create mode 100755 simu/mat2h.sh create mode 100644 simu/modelisation.slx create mode 100644 simu/simu.m diff --git a/raspberrypi/Makefile b/raspberrypi/Makefile index 4f9117e..53828a8 100644 --- a/raspberrypi/Makefile +++ b/raspberrypi/Makefile @@ -109,6 +109,7 @@ upgrade-fpga: # CHEF chef: + ../simu/mat2h.sh make -C buildroot chef-rebuild upgrade-chef: chef diff --git a/simu/.gitignore b/simu/.gitignore new file mode 100644 index 0000000..cf640b7 --- /dev/null +++ b/simu/.gitignore @@ -0,0 +1,2 @@ +*.mat +slprj/* diff --git a/simu/mat2h.py b/simu/mat2h.py new file mode 100755 index 0000000..21ee77f --- /dev/null +++ b/simu/mat2h.py @@ -0,0 +1,68 @@ +#!/usr/bin/env python3 + +import sys + +inDimensions = False + +for line in sys.stdin: + l = line.rstrip('\n') + + if inDimensions: + if l == '%END DIMENSIONS': + inDimensions = False + continue + + if l.startswith('global'): + continue + + if l.startswith('%'): + print(l.replace('%', '//')) + continue + + if l.strip() == "": + print() + continue + + out = "#define " + step = 0; + wasUpper = l[0].isupper() + for c in l: + if step == 0: + if c.isalpha(): + if c.isupper() and not wasUpper: + out += '_' + c + else: + out += c.upper() + wasUpper = c.isupper() + else: + step = 1 + elif step == 1: + if c == '=': + step = 2 + elif step == 2: + if c.isalpha(): + if c.isupper() and not wasUpper: + out += '_' + c + else: + out += c.upper() + wasUpper = c.isupper() + else: + if c == ';': + step = 3 + else: + out += c + elif step == 3: + if c == '%': + step = 4 + out += '//' + else: + out += c + elif step == 4: + out += c + + print(out.replace('PI', 'M_PI')) + + else: + if l == '%BEGIN DIMENSIONS': + inDimensions = True + continue diff --git a/simu/mat2h.sh b/simu/mat2h.sh new file mode 100755 index 0000000..fc1e52e --- /dev/null +++ b/simu/mat2h.sh @@ -0,0 +1,15 @@ +#!/usr/bin/env bash + +cd "$( dirname "${BASH_SOURCE[0]}" )" + +FILE="../chef/src/dimensions.h" + +echo -e "#ifndef __DIMENSIONS_H__ +#define __DIMENSIONS_H__ + +#include " > $FILE + +cat simu.m | ./mat2h.py >> $FILE + +echo -e "#endif" >> $FILE + diff --git a/simu/modelisation.slx b/simu/modelisation.slx new file mode 100644 index 0000000000000000000000000000000000000000..8555868d215224a2f5150a83cc50ff0381235d1a GIT binary patch literal 32512 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 P3WEXwl>L!O1@M0WL@5Y@ literal 0 HcmV?d00001 diff --git a/simu/simu.m b/simu/simu.m new file mode 100644 index 0000000..c8fa17d --- /dev/null +++ b/simu/simu.m @@ -0,0 +1,373 @@ +global SIMULATION; +SIMULATION = 0; + +% Paramètres de lecture +DIRNAME = "/home/geoffrey/CdF/cdf2018-principal/log/"; +FILENAME = "000232.csv"; +PATH = DIRNAME + FILENAME; + +% Paramètres de simulation +global SIMULATION_TIME SIMULATION_DT; +SIMULATION_TIME = 10; +SIMULATION_DT = 1e-6; + +%BEGIN DIMENSIONS + +% Dimensions pistes +global pisteWidth pisteHeight pisteOrigX pisteOrigY; +pisteWidth = 3000.0; +pisteHeight = 2000.0; +pisteOrigX = 0.0; +pisteOrigY = 0.0; + +% Dimensions robot +global width height distanceBetweenWheels wheelDiameter wheelPerimeter motorSpeedGainRPMpV motorSpeedGain motorNominalTension motorControllerAlimentation motorControllerReference motorSaturationMin motorSaturationMax pwmMax coderResolution coderDataFactor coderDataResolution cranReducOut cranReducIn reducRatio coderFullResolution avPerCycle; +width = 250.0; % mm (from meca) +height = 100.0; % mm (from random) +distanceBetweenWheels = width; % mm (from meca) +wheelDiameter = 80.0; % mm (from meca) +wheelPerimeter = (wheelDiameter * pi); % mm +motorSpeedGainRPMpV = 233.0; % rpm/V (from datasheet) +motorSpeedGain = (motorSpeedGainRPMpV / 60.0); % motor rev/s/V +motorNominalTension = 24.0; % V (from datasheet) +motorControllerAlimentation = 24.0; % V (from elec) +motorControllerReference = 5; % V (from wiring) +motorSaturationMin = 0.1; % V (from random) +motorSaturationMax = 12.0; % V (from testing) +pwmMax = 3.3; % V (from FPGA datasheet) +coderResolution = 370.0; % cycles/motor rev +coderDataFactor = 4.0; % increments/motor cycles +coderDataResolution = (coderResolution * coderDataFactor); % cycles/motor rev +cranReducOut = 48.0; % nb crans (from meca) +cranReducIn = 12.0; % nb crans (from meca) +reducRatio = (cranReducIn / cranReducOut); % reduction ratio +coderFullResolution = (coderDataResolution / reducRatio); % cycles / wheel rev +avPerCycle = (wheelPerimeter / coderFullResolution); % mm + +% Constantes asservissement +global dDirEcartMin dDirEcartMax oDirEcartMin oDirEcartMax oGain; +dDirEcartMin = 1.0; % mm +dDirEcartMax = 5.0; % mm +oDirEcartMin = (2.5 / 360.0 * 2.0 * pi); % rad +oDirEcartMax = (7.5 / 360.0 * 2.0 * pi); % rad +oGain = 1; +P = 2; +I = 0; +D = 0; + +%END DIMENSIONS + +global s; +if SIMULATION == 1 + % Génération de la consigne + xinit = 50; + yinit = 50; + oinit = 4 * pi; + d1t = 2; + d1x = 300; + d1y = -300; + d1o = 2 * pi; + dt = SIMULATION_DT; + + global xcons ycons ocons; + xcons = timeseries([xinit, xinit, d1x, d1x], [0 d1t-dt d1t SIMULATION_TIME]); + ycons = timeseries([yinit, yinit, d1y, d1y], [0 d1t-dt d1t SIMULATION_TIME]); + ocons = timeseries([oinit, oinit, d1o, d1o], [0 d1t-dt d1t SIMULATION_TIME]); + + % Simulation + disp("Lancement de la simulation"); + s = sim("modelisation", "StopTime", string(SIMULATION_TIME));%, "MinStep", string(SIMULATION_DT)); + fprintf("Simulation sampling rate: %f Hz\n", length(s.tout)/SIMULATION_TIME); +else + disp("Ouverture des données"); + T = readtable(PATH); + + % Données pratiques → données théoriques + T.time(1) = 0; + T.x = T.xConnu; + T.y = T.yConnu; + T.o = T.oConnu; + + %T.lVolt = T.lCodTot; + %T.rVolt = T.rCodTot; + + disp("Enregistrement des données"); + s = containers.Map; + for name=T.Properties.VariableNames + nameChar = char(name); + s(nameChar) = timeseries(T.(nameChar), T.time); + end + + % Modification pour faire passer comme une simu + td = getTimePoints(); + SIMULATION_TIME = td(end); + +end + + +% Graphes + +clf +global p; + +% Évolution spatiale +subplot(2, 2, 1); +initGraph +updateToTime(SIMULATION_DT); + +% Roues +p = subplot(2, 2, 2); +hold on; +timeGraph(["lVolt", "rVolt", "lErr", "rErr"]); +addLimitline(p, motorNominalTension); +addLimitline(p, -motorNominalTension); +addLimitline(p, 0); +title("Roues"); +xlabel("Temps (s)"); +ylabel("Tension (V)"); +legend("Gauche", "Droite", "Err. gauche", "Err. droite"); + +% Distance +p = subplot(2, 2, 3); +hold on; +timeGraph(["dDirEcart", "dErr"]); +addLimitline(p, dDirEcartMin); +addLimitline(p, dDirEcartMax); +title("Distance"); +xlabel("Temps (s)"); +ylabel("Distance (mm)"); +legend("Ecart direction", "Err. retenue"); + +% Rotation +p = subplot(2, 2, 4); +hold on; +timeGraph(["oDirEcart", "oEcart", "oErr"]); +addLimitline(p, oDirEcartMax); +addLimitline(p, oDirEcartMin); +addLimitline(p, -oDirEcartMax); +addLimitline(p, -oDirEcartMin); +title("Rotation"); +xlabel("Temps (s)"); +ylabel("Angle (rad)"); +legend("Ecart direction", "Ecart orientation", "Err. retenue"); + +% Fonctions + +function ts = getTS(name) + global SIMULATION s; + if SIMULATION == 1 + ts = s.(name); + else + name = char(name); + if s.isKey(name) + ts = s(name); + else + fprintf("Données inconnues : %s\n", name); + ts = timeseries(); + end + end +end + +function pt = getTimePoints() + global SIMULATION s; + if SIMULATION == 1 + pt = s.tout; + else + ts = getTS('time'); + pt = ts.Time; + end +end + +function timeGraph(series) + global SIMULATION_TIME p; + m = inf; + M = -inf; + for sname=series + serie = getTS(sname); + plot(serie); + if ~isempty(serie.Data) + m = min(m, min(serie)); + end + if ~isempty(serie.Data) + M = max(M, max(serie)); + end + end + xlim([0 SIMULATION_TIME]); + if (abs(m) ~= inf) && (abs(M) ~= inf) + ylim([m M]); + end + addTimeline(p); +end + +function addLimitline(p, x) + line(p.XLim, [x x], 'Color', [0.8 0.8 0.8]); +end + +function addTimeline(p) + global t timelines; + timeline = line([t t], p.YLim, 'Color', [0 0 0]); + timelines = [timelines timeline]; +end + +function play() + global SIMULATION_TIME speed t playing; + if playing == 1 + return + end + startCpu=cputime; + startT=t; + n=0; + playing=1; + while t