From d7e0cf77644f58f29d63d7e84a66963d9c5a265d Mon Sep 17 00:00:00 2001 From: Thierry Zamofing Date: Fri, 2 Nov 2018 16:56:25 +0100 Subject: [PATCH] usr_servo code generation --- matlab/Readme.md | 10 +- matlab/StateSpaceControlDesign.m | 128 ++++++++++--------- matlab/identifyFxFyStage.m | 8 +- matlab/observer.slx | Bin 24913 -> 26003 bytes matlab/simFxFyStage.m | 4 +- matlab/stage_closed_loop.slx | Bin 35948 -> 35507 bytes python/MXTuning.py | 123 ++++++++++++++++++- python/usr_code/Makefile | 103 ++++++++++++++++ python/usr_code/pp_proj.h | 189 +++++++++++++++++++++++++++++ python/usr_code/usralgomain.c | 114 +++++++++++++++++ python/usr_code/usrcode_template.c | 117 ++++++++++++++++++ python/usr_code/usrcode_template.h | 134 ++++++++++++++++++++ 12 files changed, 863 insertions(+), 67 deletions(-) create mode 100644 python/usr_code/Makefile create mode 100755 python/usr_code/pp_proj.h create mode 100644 python/usr_code/usralgomain.c create mode 100644 python/usr_code/usrcode_template.c create mode 100644 python/usr_code/usrcode_template.h diff --git a/matlab/Readme.md b/matlab/Readme.md index 5d2d6bd..c4f23e2 100644 --- a/matlab/Readme.md +++ b/matlab/Readme.md @@ -26,12 +26,10 @@ clear; clear global; close all; [mot1,mot2]=identifyFxFyStage(); -[pb]=simFxFyStage(mot1,1); -[ssc]=StateSpaceControlDesign(mot1,1); - -[mot1,mot2]=identifyFxFyStage(); -[pb]=simFxFyStage(mot2,2); -[ssc]=StateSpaceControlDesign(mot2,2); +[pb]=simFxFyStage(mot1); +[ssc]=StateSpaceControlDesign(mot1); +[pb]=simFxFyStage(mot2); +[ssc]=StateSpaceControlDesign(mot2); ``` diff --git a/matlab/StateSpaceControlDesign.m b/matlab/StateSpaceControlDesign.m index cd15116..2ae1427 100644 --- a/matlab/StateSpaceControlDesign.m +++ b/matlab/StateSpaceControlDesign.m @@ -1,4 +1,4 @@ -function [ssc]=StateSpaceControlDesign(mot,motid) +function [ssc]=StateSpaceControlDesign(mot) % !!! first it need to run: [mot1,mot2]=identifyFxFyStage() tobuild a motor object !!! % % builds a state space controller designed for the plant. @@ -17,18 +17,18 @@ function [ssc]=StateSpaceControlDesign(mot,motid) % https://www.youtube.com/watch?v=Lax3etc837U %ss_ol=mot.ssPlt; - ss_ol_plt=mot.ssPlt; %real plant (model of real plant) - ss_ol_plt.Name='open loop plant'; - ss_ol_mdl=mot.ssMdl;%ssMdl; %simplified model (observable,controlable) for observer - ss_ol_mdl.Name='open loop model'; + ssPlt=mot.ssPlt; %real plant (model of real plant) + ssPlt.Name='open loop plant'; + ssMdl=mot.ssMdl;%ssMdl; %simplified model (observable,controlable) for observer + ssMdl.Name='open loop model'; - [Ap,Bp,Cp,Dp]=ssdata(ss_ol_plt); - [Am,Bm,Cm,Dm]=ssdata(ss_ol_mdl); + [Ap,Bp,Cp,Dp]=ssdata(ssPlt); + [Am,Bm,Cm,Dm]=ssdata(ssMdl); %sys=ss(sys.A,sys.B,sys.C(3,:),0); % this would reduce the outputs to position only - figure();h=bodeplot(ss_ol_plt,ss_ol_mdl); + figure();h=bodeplot(ssPlt,ssMdl); setoptions(h,'IOGrouping','all') % step answer on open loop: @@ -37,8 +37,8 @@ function [ssc]=StateSpaceControlDesign(mot,motid) xp0 = zeros(1,length(Ap)); xm0 = zeros(1,length(Am)); - [yp,t,x] = lsim(ss_ol_plt,u,t,xp0); - [ym,t,x] = lsim(ss_ol_mdl,u,t,xm0); + [yp,t,x] = lsim(ssPlt,u,t,xp0); + [ym,t,x] = lsim(ssMdl,u,t,xm0); figure();plot(t,yp,t,ym,'--');title('step on open loop (plant and model)'); legend('plt.iqMeas','plt.iqVolts','plt.actPos','mdl.iqMeas','mdl.iqVolts','mdl.actPos') @@ -51,44 +51,52 @@ function [ssc]=StateSpaceControlDesign(mot,motid) % *** space state controller *** % %place poles for the controller feedback - if motid==1 - %2500rad/s = 397Hz -> locate poles here - %6300rad/s = 1027Hz -> locate poles here - if length(poles)==4 - p1=-6300+2800i; - p2=-6200+1500i; - P=[p1 p1' p2 p2']; - else - p1=-3300+2800i; - p2=-2700+500i; - p3=-2500+10i; - %p1=-3300+2800i; - %p2=-1500+500i; - %p3=-1200+10i; - P=[p1 p1' p2 p2' p3 p3']; - end + use_lqr=0; + if use_lqr %use the lqr controller + Q=eye(length(ssMdl.A)); + R=1; + [K,P,E]=lqr(ssMdl,Q,R,0); else - %2500rad/s = 397Hz -> locate poles here - %6300rad/s = 1027Hz -> locate poles here - if length(poles)==4 - p1=-6300+2800i; - p2=-6200+1500i; - P=[p1 p1' p2 p2']; + if mot.id==1 + %2500rad/s = 397Hz -> locate poles here + %6300rad/s = 1027Hz -> locate poles here + if length(poles)==4 + p1=-6300+280i; + p2=-6200+150i; + P=[p1 p1' p2 p2']; + else + p1=-3300+2800i; + p2=-2700+500i; + p3=-2500+10i; + %p1=-3300+2800i; + %p2=-1500+500i; + %p3=-1200+10i; + P=[p1 p1' p2 p2' p3 p3']; + end else - p1=-3300+2800i; - p2=-1900+130i; - p3=-2900+80i; - p4=-2300+450i; - p5=-2000+20i; - p6=-1500+10i; - %p1=-3300+2800i; - %p2=-1500+500i; - %p3=-1200+10i; - P=[p1 p1' p2 p2' p3 p3'];% p4 p4' p5 p5' p6 p6']; + %2500rad/s = 397Hz -> locate poles here + %6300rad/s = 1027Hz -> locate poles here + if length(poles)==4 + p1=-6300+2800i; + p2=-6200+1500i; + P=[p1 p1' p2 p2']; + else + p1=-3300+2800i; + p2=-1900+130i; + p3=-2900+80i; + p4=-2300+450i; + p5=-2000+20i; + p6=-1500+10i; + %p1=-3300+2800i; + %p2=-1500+500i; + %p3=-1200+10i; + P=[p1 p1' p2 p2' p3 p3'];% p4 p4' p5 p5' p6 p6']; + end end - end - K = place(Am,Bm,P); - %K = acker(Am,Bm,Pm); + K = place(Am,Bm,P); + %K = acker(Am,Bm,Pm); + end %if lqr + V=-1./(Cm*(Am-Bm*K)^-1*Bm); %(from Lineare Regelsysteme2 (Glattfelder) page:173 ) %Nbar(2)=1; %the voltage stuff is crap for now if length(V)>1 @@ -110,7 +118,7 @@ function [ssc]=StateSpaceControlDesign(mot,motid) % *** observer controller *** % %observer poles-> 5 times farther left than system poles - if motid==1 + if mot.id==1 op1=(p1*5); op2=(p2*5); if length(poles)>4 @@ -143,27 +151,27 @@ function [ssc]=StateSpaceControlDesign(mot,motid) Ct = [ Cm zeros(size(Cm)) ]; % step answer on closed loop with observer controller: - ss_o = ss(At,Bt,Ct,0,'Name','observer controller','InputName',{'desPos'},'OutputName',mot.ssMdl.OutputName); - figure();lsim(ss_o,ones(size(t)),t,[xm0 xm0]);title('step on closed loop with observer'); + ss_t = ss(At,Bt,Ct,0,'Name','observer controller','InputName',{'desPos'},'OutputName',mot.ssMdl.OutputName); + figure();lsim(ss_t,ones(size(t)),t,[xm0 xm0]);title('step on closed loop with observer'); % *** disctrete observer controller *** % Ts=1/5000; % 5kHz - ss_od = c2d(ss_o,Ts); - ss_od .Name='discrete obsvr ctrl'; + ss_tz = c2d(ss_t,Ts); + ss_tz .Name='discrete obsvr ctrl'; % step answer on closed loop with disctrete observer controller: t = 0:Ts:.05; - figure();lsim(ss_od ,ones(size(t)),t,[xm0 xm0]);title('step on closed loop with observer discrete'); + figure();lsim(ss_tz ,ones(size(t)),t,[xm0 xm0]);title('step on closed loop with observer discrete'); %plot all bode diagrams of desPos->actPos figure(); - h=bodeplot(ss_cl(3),ss_o(3),ss_od(3)); + h=bodeplot(ss_cl(3),ss_t(3),ss_tz(3)); setoptions(h,'FreqUnits','Hz','Grid','on');legend('location','sw'); figure(); - h=pzplot(ss_cl(3),ss_o(3),ss_od(3)); + h=pzplot(ss_cl(3),ss_t(3),ss_tz(3)); setoptions(h,'FreqUnits','Hz','Grid','on');legend('location','sw'); @@ -172,15 +180,25 @@ function [ssc]=StateSpaceControlDesign(mot,motid) Bo=[Bm L]; Co=K; Do=zeros(size(Co,1),size(Bo,2)); + + ss_o = ss(Ao,Bo,Co,Do,'Name','observer controller','InputName',{'desPos','iqMeas','iqVolts','actPos'},'OutputName',{'k*xt'}); + + ss_oz = c2d(ss_o,Ts); + [Aoz,Boz,Coz,Doz]=ssdata(ss_oz); mdlName='observer'; open(mdlName); + +ssPltz = c2d(ssPlt,Ts); +[Apz,Bpz,Cpz,Dpz]=ssdata(ssPltz); + + %state space controller ssc=struct(); - for k=["Ts","Ap","Bp","Cp","Dp","Ao","Bo","Co","Do","V","K","L","ss_cl","ss_o","ss_od","numV","denV"] + for k=["Ts","Ap","Bp","Cp","Dp","Ao","Bo","Co","Do","Apz","Bpz","Cpz","Dpz","Aoz","Boz","Coz","Doz","V","K","L","ss_cl","ss_o","ss_oz","numV","denV"] ssc=setfield(ssc,k,eval(k)); end - + save(sprintf('/tmp/ssc%d.mat',mot.id),'-struct','ssc'); end diff --git a/matlab/identifyFxFyStage.m b/matlab/identifyFxFyStage.m index 5bf2470..bba9884 100644 --- a/matlab/identifyFxFyStage.m +++ b/matlab/identifyFxFyStage.m @@ -101,7 +101,9 @@ function [mot1,mot2]=identifyFxFyStage() end function mot=fyStage() - mot=loadData('/home/zamofing_t/Documents/prj/SwissFEL/epics_ioc_modules/ESB_MX/python/MXTuning/18_10_02/',1); + motid=1; + mot=loadData('/home/zamofing_t/Documents/prj/SwissFEL/epics_ioc_modules/ESB_MX/python/MXTuning/18_10_02/',motid); + mot.id=motid; mot.tfc=currstep(mot); opt=tfestOptions; @@ -171,7 +173,9 @@ function [mot1,mot2]=identifyFxFyStage() end function mot=fxStage() - mot=loadData('/home/zamofing_t/Documents/prj/SwissFEL/epics_ioc_modules/ESB_MX/python/MXTuning/18_10_02/',2); + motid=2; + mot=loadData('/home/zamofing_t/Documents/prj/SwissFEL/epics_ioc_modules/ESB_MX/python/MXTuning/18_10_02/',motid); + mot.id=motid; currstep(mot); opt=tfestOptions; diff --git a/matlab/observer.slx b/matlab/observer.slx index 2ad9c104b94167bce4fd18b06a9314740a66aed8..9e2673c5b669ef1418b252f41b0bc70c9e42ae6a 100644 GIT binary patch delta 21702 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≫EIh$TECB;wk=M~F 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 diff --git a/matlab/simFxFyStage.m b/matlab/simFxFyStage.m index 9449d75..72e0652 100644 --- a/matlab/simFxFyStage.m +++ b/matlab/simFxFyStage.m @@ -1,4 +1,4 @@ -function [pb]=simFxFyStage(mot,motid) +function [pb]=simFxFyStage(mot) % !!! first it need to run: [mot1,mot2]=identifyFxFyStage() tobuild a motor object !!! % %loads the current (11.10.2018) controller settings of the @@ -9,7 +9,7 @@ function [pb]=simFxFyStage(mot,motid) Ts=2E-4; % 0.2ms=5kHz MaxDac=2011.968; MaxPosErr=10000; - if motid==1 + if mot.id==1 %!motor_servo(mot=1,ctrl='ServoCtrl',Kp=25,Kvfb=400,Ki=0.02,Kvff=350,Kaff=5000,MaxInt=1000) %!motor(mot=1,dirCur=0,contCur=800,peakCur=2400,timeAtPeak=1,IiGain=5,IpfGain=8,IpbGain=8,JogSpeed=10.,numPhase=3,invDir=True,servo=None,PhasePosSf=1./81250,PhaseFindingDac=100,PhaseFindingTime=50,SlipGain=0,AdvGain=0,PwmSf=10000,FatalFeLimit=200,WarnFeLimit=100,InPosBand=2,homing='enc-index') Kp=25;Kvfb=400;Ki=0.02;Kvff=350;Kaff=5000;MaxInt=1000; diff --git a/matlab/stage_closed_loop.slx b/matlab/stage_closed_loop.slx index c0b16691fe3e840f8d5c442b262937de4b3313e5..0a29f9a1fff79aef90fc1653bfcc78244f15ebf8 100644 GIT binary patch delta 15236 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 diff --git a/python/MXTuning.py b/python/MXTuning.py index 53cc6cb..30d7c14 100755 --- a/python/MXTuning.py +++ b/python/MXTuning.py @@ -15,6 +15,8 @@ Modes: 4 plot the full bode recording 5 plot the full bode recording with an approximation model 6 plot all raw acquired data files +7 custom chirp test +8 generate observer code (after files generated with matlab) -> check https://github.com/klauer/ppmac for fast data gathering server which supports phase gathering -> not yet compiling: /home/zamofing_t/Documents/prj/SwissFEL/PowerBrickInspector/ppmac/fast_gather @@ -201,6 +203,90 @@ class MXTuning(Tuning): ax.semilogx(f, phase,'-k',lw=1) # Bode phase plot # tp print see also: print(np.poly1d([1,2,3], variable='s')), print(np.poly1d([1,2,3], r=True, variable='s')) + def usr_servo_gen_code(self,fn='/tmp/ssc1.mat'): + import scipy.io,re + #the file ssc[1|2].mat has been generated with matlab: + #[mot1, mot2]=identifyFxFyStage(); + #[pb]=simFxFyStage(mot1); + #[ssc]=StateSpaceControlDesign(mot1); + mat=scipy.io.loadmat(fn) + motid=int(re.search('(\d)\.mat',fn).group(1)) + A=mat['Aoz'] + B=mat['Boz'] + C=mat['Coz'] + D=mat['Doz'] + V=mat['V'] + u=('DesPos','IqMeas','IqVolts','ActPos') + y=('obsvOut',) + progSample='''double usr_servo_ctrl_{motid}(MotorData *Mptr) +{{ + pshm->P[2000]=pshm->P[2000]*.9999+abs(Mptr->PosError)*0.0001; //lowpass of Position error + return pshm->ServoCtrl(Mptr); +}}'''.format(motid=motid) + + prog='''double obsvr_servo_ctrl_{motid}(MotorData *Mptr) +{{ + //x[n+1]=A*x[n]+B*u + //y=C*x[n]+D*x[n] + //u=[{u}].T + double x[{A.shape[0]}]; //new state + static double _x[{A.shape[0]}]={{0,0,0,0}}; //old state + //double {u}; // input values + double {y},iqCmd; // output values + double maxDac=Mptr->MaxDac; +'''.format(motid=motid,A=A,xInit=','.join('0'*A.shape[0]),u=', '.join(u),y=', '.join(y)) + s=' //input values\n' + for i in range(len(u)): + s+=' double {u}=Mptr->{u};\n'.format(u=u[i]) + prog+=s+'''\n + if (Mptr->ClosedLoop) + { + return iqCmd; + } + else + { + Mptr->Servo.Integrator=0.0; + return 0.0; + } +''' + + s=' //x[n+1]=A*x[n]+B*u;\n' + for i in range(A.shape[0]): + s+=' x[%d]='%i + for j in range(A.shape[1]): + s+='%+28.22g*_x[%d]'%(A[i,j],j) + for j in range(B.shape[0]): + s+='%+28.22g*%s'%(B[i,j],u[j]) + s+=';\n' + prog+=s+'\n' + + s=' //y=C*x[n]+D*x[n];\n' + for i in range(C.shape[0]): + s+=' %s='%y[i] + for j in range(C.shape[1]): + s+='%+28.22g*_x[%d]'%(C[i,j],j) + s+=';\n' + prog+=s+'\n' + + + prog+=''' iqCmd=DesPos*{V}-{y}; + if (iqCmd>maxDac) + {{ + iqCmd=maxDac; + }} + else + {{ + if (iqCmd<-maxDac) + {{ + iqCmd=-maxDac; + }} + }} + return iqCmd; +}}'''.format(V=V[0,0],y=y[0]) + + hdr='''double obsvr_servo_ctrl_{motid}(MotorData *Mptr); +EXPORT_SYMBOL(obsvr_servo_ctrl_{motid});'''.format(motid=motid) + return (hdr,prog) def bode(mdl): w,mag,phase = signal.bode(mdl,1000) @@ -250,6 +336,7 @@ Examples:'''+''.join(map(lambda s:cmd+s, exampleCmd))+'\n ' #plt.ion() args.host='MOTTEST-CPPM-CRM0573' + args.host=None if args.host is None: comm=gt=None else: @@ -342,10 +429,42 @@ Examples:'''+''.join(map(lambda s:cmd+s, exampleCmd))+'\n ' tune.custom_chirp(motor=1,minFrq=100,maxFrq=3000,amp=10,tSec=5,mode=0,file='/tmp/cst_chirp0.npz') #tune.custom_chirp(motor=2,minFrq=1,maxFrq=1000,tSec=5,mode=1,file='/tmp/cst_chirp1.npz') #tune.custom_chirp(motor=1,minFrq=1,maxFrq=3000,tSec=5,mode=2,file='/tmp/cst_chirp2.npz') - + elif mode==8: #generater code + #before this can be done, the observer controller has to be designed with matlab: + #s.a.ESB_MX/matlab/Readme.md + #clear; + #clear global; + #close all; + #[mot1,mot2]=identifyFxFyStage(); + #[pb]=simFxFyStage(mot1); + #[ssc]=StateSpaceControlDesign(mot1); + #[pb]=simFxFyStage(mot2); + #[ssc]=StateSpaceControlDesign(mot2); + #after this go to: python/usr_code and call make to build the controller + #to activate the controller checkout: PBTools/pbtools/usr_servo_phase + base=os.path.dirname(__file__) + (hdr1,prog1)=tune.usr_servo_gen_code('/tmp/ssc1.mat') + (hdr2,prog2)=tune.usr_servo_gen_code('/tmp/ssc2.mat') + fn_ct=os.path.join(base,'usr_code/usrcode_template.c') + fn_ht=os.path.join(base,'usr_code/usrcode_template.h') + fnc=os.path.join(base,'usr_code/usrcode.c') + fnh=os.path.join(base,'usr_code/usrcode.h') + s=open(fn_ht).read() + s=s.replace('',hdr1+'\n\n'+hdr2) + fh=open(fnh,'w') + fh.write(s) + fh.close() + print(fnh+' generated.') + s=open(fn_ct).read() + s=s.replace('',prog1+'\n\n'+prog2) + fh=open(fnc,'w') + fh.write(s) + fh.close() + print(fnc+' generated.') + print('now compile it looking at PBTools/pbtools/usr_servo_phase/usrServoSample') plt.show() #------------------ Main Code ---------------------------------- - #ssh_test() + #ssh_test()'/tmp/usrcode.c' ret=parse_args() exit(ret) diff --git a/python/usr_code/Makefile b/python/usr_code/Makefile new file mode 100644 index 0000000..600d19b --- /dev/null +++ b/python/usr_code/Makefile @@ -0,0 +1,103 @@ +#------------------------------------------------------------------------------ +# Copyright (C) Delta Tau Data Systems Inc., 2007 +# All rights reserved. +# +# Generic makefile for any c realtime C plc 0, user servo or user phase +# For a new project change the following +# +# 1.) usralgo-objs should be assigned the 'C' source code files that need to be compiled +# 2.) issue the command 'make depend' the first time a project is created and +# (every time an additional 'C' file is added to the project the command +# 'make depend' must be issued) +# 3.) issue the command make clean +# 4.) issue the command make +# +# Notes +# -------- +# Change DTDEBUG above to -O2 for release w/ optimization +# Change DTDEBUG above to -g3 for debug +# arm,i386,i385hv,ppc460-2,ppc460-1,ppc405 +#------------------------------------------------------------------------------ + +PPMAC=SAR-CPPM-EXPMX1 +PPMAC=MOTTEST-CPPM-CRM0573 +#PPMAC=SAROP11-CPPM-MOT6871 + +PMAC_ARCH=ppc465-2 + +ifeq ($(PMAC_ARCH),ppc465-2) +ARCH=powerpc +#CROSS_COMPILE=powerpc-meau-linux-gnu- +CROSS_COMPILE=/opt/eldk-4.2/usr/bin/ppc_4xxFP- +KDIR=/opt/powerpc-465-rootfs/usr/src/linux-3.2.21-serengeti-smp +KSRC=/opt/powerpc-465-rootfs/usr/src/linux-3.2.21-serengeti-smp +#CC=powerpc-meau-linux-gnu-gcc +#AS=powerpc-meau-linux-gnu-as +#LD=powerpc-meau-linux-gnu-gcc +CC=/opt/eldk-4.2/usr/bin/ppc_4xxFP-gcc +AS=/opt/eldk-4.2/usr/bin/ppc_4xxFP-gcc +LD=/opt/eldk-4.2/usr/bin/ppc_4xxFP-gcc +#STRIP=i686-meau-linux-gnu-strip +INCLUDE=/opt/powerpc-465-rootfs/usr/lib/gcc/powerpc-linux-gnu/4.6/include +XENOMAI_INC_DIR=/opt/powerpc-465-rootfs/usr/local/xenomai-2.6.2.1/include +XENOMAI_LIB_DIR=/opt/powerpc-465-rootfs/usr/local/xenomai-2.6.2.1/lib +RPATH=-Wl,-rpath-link,/opt/powerpc-465-rootfs/lib/powerpc-linux-gnu +ROOTFS_DIR=/opt/powerpc-465-rootfs +endif + +#RTPMACINCLUDEDIR=/usr/local/dtlibs/rtpmac +#LIBPPMACINCLUDEDIR=/usr/local/dtlibs/libppmac +#THESE PATHS MUST BE ABSOLUTE ! +RTPMACINCLUDEDIR=/opt/eldk-4.2/PPMAC_rootfs-7-wheezy/opt/ppmac/rtpmac/ +LIBPPMACINCLUDEDIR=/opt/eldk-4.2/PPMAC_rootfs-7-wheezy/opt/ppmac/libppmac/ + +export ARCH +export CROSS_COMPILE + +OBJS := ${patsubst %, %.o, $(MODULES)} +CLEANMOD := ${patsubst %, .%*, $(MODULES)} +PWD := $(shell if [ "$$PWD" != "" ]; then echo $$PWD; else pwd; fi) + + +obj-m += usralgo.o +usralgo-objs := usralgomain.o \ +usrcode.o + +LDFLAGS := -nostdlib +EXTRA_CFLAGS := -O2 -DCONFIG_460EX -D_GNU_SOURCE -D_REENTRANT -D__XENO__ -mhard-float -I$(RTPMACINCLUDEDIR) -I$(LIBPPMACINCLUDEDIR) -I$(XENOMAI_INC_DIR) -I$(XENOMAI_INC_DIR)/posix -I$(KSRC)/include/xenomai -I$(KSRC)/include/xenomai/posix -I$(INCLUDE) $(ADD_CFLAGS) --sysroot=$(ROOTFS_DIR) +KBUILD_EXTRA_SYMBOLS := /usr/local/dtlibs/libppmac/Module.symvers + +%.o: %.S + $(CC) -s -D__KERNEL__ -x c -E $< -o $*.i + $(AS) -mbooke -o $@ $*.i + +#all:: +# cp -f /usr/local/usralgo/usralgomain.c $(PWD) +all: + $(MAKE) -C $(KSRC) SUBDIRS=$(PWD) modules + #scp usralgo.ko root@$(PPMAC):/tmp + #scp pp_proj.ini root@$(PPMAC):/var/ftp/usrflash/Project/Configuration/pp_proj.ini + #scp pp_proj.ini root@$(PPMAC):/tmp/pp_proj.ini + #ssh root@$(PPMAC) projpp + +# $(MAKE) -C $(KSRC) SUBDIRS=$(PWD) modules V=1 +# mv -f usralgo.ko ../../bin/Debug/ + + +#modules: +# @echo "$(CFLAGS)" + +bclean:: + $(RM) *.o .*.o.d .*.o.cmd *.ko *.log + $(RM) -R .tmp* + $(RM) .runinfo + rm -rf .runinfo .tmp* .*.o.d .*.o.cmd .*.cmd *.o *.ko *.mod.c *.i *.so Module.symvers modules.order + +clean:: + $(RM) *.o .*.o.d .*.o.cmd *.ko + $(RM) -R .tmp* + $(RM) .runinfo + rm -rf .runinfo .tmp* .*.o.d .*.o.cmd .*.cmd *.o *.ko *.mod.c *.i *.so Module.symvers modules.order + +dbg: + @echo PATH $(PATH) diff --git a/python/usr_code/pp_proj.h b/python/usr_code/pp_proj.h new file mode 100755 index 0000000..2dec7b8 --- /dev/null +++ b/python/usr_code/pp_proj.h @@ -0,0 +1,189 @@ + +#ifndef _PP_PROJ_H_ +#define _PP_PROJ_H_ +//*********************************************************************************** +// C header for accessing PMAC Global, CSGlobal, Ptr vars +// _PPScriptMode_ for Pmac Script like access global & csglobal +// global Mypvar - access with "Mypvar" +// global Myparray(32) - access with "Myparray(i)" +// csglobal Myqvar - access with "Myqvar(i)" where "i" is Coord # +// csglobal Myqarray(16) - access with "Myqvar(i,j)" where "j" is index +// _EnumMode_ for Pmac enum data type checking on Set & Get global functions +// Example +// global Mypvar +// csglobal Myqvar +// "SetGlobalVar(Myqvar, data)" will give a compile error because its a csglobal var. +// "SetCSGlobalVar(Mypvar, data)" will give a compile error because its a global var. +//************************************************************************************ + +#ifdef _PPScriptMode_ +enum globalP {_globalP_=-1}; +enum globalParray {_globalParray_=-1}; +enum csglobalQ {_csglobalQ_=-1}; +enum csglobalQarray {_csglobalQarray_=-1}; + +enum ptrM {_ptrM_=-1}; +enum ptrMarray {_ptrMarray_=-1}; +void SetEnumGlobalVar(enum globalP var, double data) +{ + pshm->P[var] = data; +} + +double GetEnumGlobalVar(enum globalP var) +{ + return pshm->P[var]; +} + +void SetEnumGlobalArrayVar(enum globalParray var, unsigned index, double data) +{ + pshm->P[(var + index)%MAX_P] = data; +} + +double GetEnumGlobalArrayVar(enum globalParray var, unsigned index) +{ + return pshm->P[(var + index)%MAX_P]; +} + +void SetEnumCSGlobalVar(enum csglobalQ var, unsigned cs, double data) +{ + pshm->Coord[cs % MAX_COORDS].Q[var] = data; +} + +double GetEnumCSGlobalVar(enum csglobalQ var, unsigned cs) +{ + return pshm->Coord[cs % MAX_COORDS].Q[var]; +} + +void SetEnumCSGlobalArrayVar(enum csglobalQarray var, unsigned index, unsigned cs, double data) +{ + pshm->Coord[cs % MAX_COORDS].Q[(var + index)%MAX_Q] = data; +} + +double GetEnumCSGlobalArrayVar(enum csglobalQarray var, unsigned index, unsigned cs) +{ + return pshm->Coord[cs % MAX_COORDS].Q[(var + index)%MAX_Q]; +} + +void SetEnumPtrVar(enum ptrM var, double data) +{ + im_write(pshm->Mdef + var, data, &pshm->Ldata); +} + +double GetEnumPtrVar(enum ptrM var) +{ + return im_read(pshm->Mdef + var, &pshm->Ldata); +} + +void SetEnumPtrArrayVar(enum ptrMarray var, unsigned index, double data) +{ + im_write(pshm->Mdef + ((var + index)%MAX_M), data, &pshm->Ldata); +} + +double GetEnumPtrArrayVar(enum ptrMarray var, unsigned index) +{ + return im_read(pshm->Mdef + ((var + index)%MAX_M), &pshm->Ldata); +} + +#define SetGlobalVar(i, x) SetEnumGlobalVar(i, x) +#define SetGlobalArrayVar(i, j, x) SetEnumGlobalArrayVar(i, j, x) +#define GetGlobalVar(i) GetEnumGlobalVar(i) +#define GetGlobalArrayVar(i, j) GetEnumGlobalArrayVar(i, j) + +#define SetCSGlobalVar(i, j, x) SetEnumCSGlobalVar(i, j, x) +#define SetCSGlobalArrayVar(i, j, k, x) SetEnumCSGlobalArrayVar(i, j, k, x) +#define GetCSGlobalVar(i, j) GetEnumCSGlobalVar(i, j) +#define GetCSGlobalArrayVar(i, j, k) GetEnumCSGlobalArrayVar(i, j, k) + +#define SetPtrVar(i, x) SetEnumPtrVar(i, x) +#define SetPtrArrayVar(i, j, x) SetEnumPtrArrayVar(i, j, x) +#define GetPtrVar(i) GetEnumPtrVar(i) +#define GetPtrArrayVar(i, j) GetEnumPtrArrayVar(i, j) +// end of #ifdef _PPScriptMode_ +#else +#ifdef _EnumMode_ +enum globalP {_globalP_=-1}; +enum globalParray {_globalParray_=-1}; +enum csglobalQ {_csglobalQ_=-1}; +enum csglobalQarray {_csglobalQarray_=-1}; +enum ptrM {_ptrM_=-1}; +enum ptrMarray {_ptrMarray_=-1}; +void SetEnumGlobalVar(enum globalP var, double data) +{ + pshm->P[var] = data; +} + +double GetEnumGlobalVar(enum globalP var) +{ + return pshm->P[var]; +} + +void SetEnumGlobalArrayVar(enum globalParray var, unsigned index, double data) +{ + pshm->P[(var + index)%MAX_P] = data; +} + +double GetEnumGlobalArrayVar(enum globalParray var, unsigned index) +{ + return pshm->P[(var + index)%MAX_P]; +} + +void SetEnumCSGlobalVar(enum csglobalQ var, unsigned cs, double data) +{ + pshm->Coord[cs % MAX_COORDS].Q[var] = data; +} + +double GetEnumCSGlobalVar(enum csglobalQ var, unsigned cs) +{ + return pshm->Coord[cs % MAX_COORDS].Q[var]; +} + +void SetEnumCSGlobalArrayVar(enum csglobalQarray var, unsigned index, unsigned cs, double data) +{ + pshm->Coord[cs % MAX_COORDS].Q[(var + index)%MAX_Q] = data; +} + +double GetEnumCSGlobalArrayVar(enum csglobalQarray var, unsigned index, unsigned cs) +{ + return pshm->Coord[cs % MAX_COORDS].Q[(var + index)%MAX_Q]; +} + +void SetEnumPtrVar(enum ptrM var, double data) +{ + im_write(pshm->Mdef + var, data, &pshm->Ldata); +} + +double GetEnumPtrVar(enum ptrM var) +{ + return im_read(pshm->Mdef + var, &pshm->Ldata); +} + +void SetEnumPtrArrayVar(enum ptrMarray var, unsigned index, double data) +{ + im_write(pshm->Mdef + ((var + index)%MAX_M), data, &pshm->Ldata); +} + +double GetEnumPtrArrayVar(enum ptrMarray var, unsigned index) +{ + return im_read(pshm->Mdef + ((var + index)%MAX_M), &pshm->Ldata); +} + +#define SetGlobalVar(i, x) SetEnumGlobalVar(i, x) +#define SetGlobalArrayVar(i, j, x) SetEnumGlobalArrayVar(i, j, x) +#define GetGlobalVar(i) GetEnumGlobalVar(i) +#define GetGlobalArrayVar(i, j) GetEnumGlobalArrayVar(i, j) + +#define SetCSGlobalVar(i, j, x) SetEnumCSGlobalVar(i, j, x) +#define SetCSGlobalArrayVar(i, j, k, x) SetEnumCSGlobalArrayVar(i, j, k, x) +#define GetCSGlobalVar(i, j) GetEnumCSGlobalVar(i, j) +#define GetCSGlobalArrayVar(i, j, k) GetEnumCSGlobalArrayVar(i, j, k) + +#define SetPtrVar(i, x) SetEnumPtrVar(i, x) +#define SetPtrArrayVar(i, j, x) SetEnumPtrArrayVar(i, j, x) +#define GetPtrVar(i) GetEnumPtrVar(i) +#define GetPtrArrayVar(i, j) GetEnumPtrArrayVar(i, j) +// end of #ifdef _EnumMode_ +#else +// ***** Standard default mode ***** +#endif +#endif +#endif //_PP_PROJ_H_ diff --git a/python/usr_code/usralgomain.c b/python/usr_code/usralgomain.c new file mode 100644 index 0000000..3232aa8 --- /dev/null +++ b/python/usr_code/usralgomain.c @@ -0,0 +1,114 @@ +//--------------------------------------------------------------------------- +// Project PowerPMAC Firmware +// Delta Tau Data Systems, Inc. +// Copyright 2007. All Rights Reserved. +// +// SUBSYSTEM: User Algo Driver +// FILE: usralgo.c +// AUTH OR: Henry Bausley +// +// OVERVIEW +// ~~~~~~~~ +// This file is a device driver that exports functions that can be used by other +// kernel mode modules. ie. RtPmac.rtl can call functions that are part of this +// driver for use as user written servo, phase, plc rti, plc rt thread +// No one should ever have to touch this module! Custom routines are added +// as additional modules as whatever name the user wants. +// +// NOTES +// ~~~~~ +// - The driver must be loaded +// bash-3.0# insmod /opt/ppmac/usralgo/usralgo.ko +// +// - A node can be created on the file system the thing you fopen +// but it is not required. Could be used by gpos if ioctl's were added +// bash-3.0# mknod -m 666 /dev/usralgo c 240 0 +// +//-------------------------------------------------------------------------------- +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + + +//#define KDBEUG 1 + +#ifdef KDBEUG + #define PRINTK(arg) printk(arg) +#else + #define PRINTK(arg) +#endif + +#define USRALGO_MAJOR 240 +#define USRALGO_NAME "usralgo" + +struct SHM *pshm; // Pointer to shared memory +volatile unsigned *piom; // Pointer to I/O memory +void *pushm; // Pointer to user memory + + +// define which file operations are supported +struct file_operations usralgo_fops = +{ + .owner = THIS_MODULE, + .llseek = NULL, + .read = NULL, + .write = NULL, +// .readdir = NULL, + .poll = NULL, +#if LINUX_VERSION_CODE < KERNEL_VERSION(3,0,0) + .ioctl = NULL, +#else + .unlocked_ioctl = NULL, +#endif + .mmap = NULL, + .open = NULL, + .flush = NULL, + .release = NULL, + .fsync = NULL, + .fasync = NULL, + .lock = NULL, +}; + +//----------------------------------------------------------------------- +// initialize module -- this what is called when you do insmod ./usralgo.ko +//----------------------------------------------------------------------- +static int __init usralgo_init_module (void) +{ + int i; + + PRINTK(KERN_INFO "initializing module usralgo\n"); + pshm = GetSharedMemPtr(); + pushm = GetUserBufferPtr(); + piom = GetIOMemPtr(); + + i = register_chrdev (USRALGO_MAJOR, USRALGO_NAME, &usralgo_fops); + if (i != 0) return - EIO; + + return 0; +} + +//----------------------------------------------------------------------- +// close and cleanup module +//------------------------- +static void __exit usralgo_cleanup_module (void) +{ + PRINTK("cleaning up module usralgo\n"); + unregister_chrdev (USRALGO_MAJOR, USRALGO_NAME); +} + +module_init(usralgo_init_module); +module_exit(usralgo_cleanup_module); +MODULE_AUTHOR("www.deltatau.com"); +MODULE_LICENSE("GPL"); +MODULE_DESCRIPTION("Linux Device Driver for usralgo"); diff --git a/python/usr_code/usrcode_template.c b/python/usr_code/usrcode_template.c new file mode 100644 index 0000000..f96d502 --- /dev/null +++ b/python/usr_code/usrcode_template.c @@ -0,0 +1,117 @@ +//--------------------------------------------------------------------------- +// Project PowerPMAC Firmware +// Delta Tau Data Systems, Inc. +// Copyright 2007. All Rights Reserved. +// +// SUBSYSTEM: User Servo Driver +// FILE: usrcode.c +// TEMPLATE AUTHOR: Henry Bausley +// +// OVERVIEW +// ~~~~~~~~ +// This file is where exportable user code can be placed. +// To make a function callable as a user servo do three steps +// +// 1.) Prototye the function user_func(void ,void ); +// 2.) Export the function EXPORT_SYMBOL(user_func); +// 3.) Make sure useralgo.ko has been loaded with projpp.ini +// +//-------------------------------------------------------------------------------- +#include "usrcode.h" +//---------------------------------------------------------------------------------- +// pp_proj.h is the C header for accessing PMAC Global, CSGlobal, Ptr vars +// _PPScriptMode_ for Pmac Script like access global & csglobal +// global Mypvar - access with "Mypvar" +// global Myparray(32) - access with "Myparray(i)" +// csglobal Myqvar - access with "Myqvar(i)" where "i" is Coord # +// csglobal Myqarray(16) - access with "Myqvar(i,j)" where "j" is index +// _EnumMode_ for Pmac enum data type checking on Set & Get global functions +// Example +// global Mypvar +// csglobal Myqvar +// "SetGlobalVar(Myqvar, data)" will give a compile error because its a csglobal var. +// "SetCSGlobalVar(Mypvar, data)" will give a compile error because its a global var. +//------------------------------------------------------------------------------------ +#define _PPScriptMode_ // uncomment for Pmac Script type access +// #define _EnumMode_ // uncomment for Pmac enum data type checking on Set & Get global functions + +#include "pp_proj.h" +#ifdef __KERNEL__ +// Kernal mode can't have paths with spaces and long names +//#include "../../PMACSC~1/GLOBAL~1/asharedwithcapp.pmh" +#else +//#include "../../PMAC Script Language/Global Includes/asharedwithcapp.pmh" +#endif + +extern struct SHM *pshm; // Pointer to shared memory +extern volatile unsigned *piom; // Pointer to I/O memory +extern void *pushm; // Pointer to user memory + + + +void user_phase_sample( struct MotorData *Mptr) +{ +} + +double usr_servo_sample(MotorData *Mptr) +{ + pshm->P[2000]=pshm->P[2000]*.9999+abs(Mptr->PosError)*0.0001; //lowpass of Position error + return pshm->ServoCtrl(Mptr); +} + +//double user_pid_ctrl( struct MotorData *Mptr) +//{ +// //double *p; +// //p = pushm; +// //return 0; +// double ctrl_out; +// if (Mptr->ClosedLoop) { +// // Compute PD terms +// ctrl_out=Mptr->Servo.Kp*Mptr->PosError-Mptr->Servo.Kvfb*Mptr->ActVel; +// Mptr->Servo.Integrator+=Mptr->PosError*Mptr->Servo.Ki; // I term +// ctrl_out+=Mptr->Servo.Integrator; +// // Combine +// if (ctrl_out>2000)ctrl_out=2000; +// if (ctrl_out<-2000)ctrl_out=-2000; +// return ctrl_out; +// } +// else { +// Mptr->Servo.Integrator=0.0; +// return 0.0; +// } +//} + +void CaptCompISR(void) +{ + unsigned *pUnsigned = pushm; + *pUnsigned = *pUnsigned + 1; +} + +double GetLocal(struct LocalData *Ldata,int m) +{ + return *(Ldata->L + Ldata->Lindex + m); +} + +void SetLocal(struct LocalData *Ldata,int m,double value) +{ + *(Ldata->L + Ldata->Lindex + m) = value; +} + +double *GetLocalPtr(struct LocalData *Ldata,int m) +{ + return (Ldata->L + Ldata->Lindex + m); +} + +double CfromScript(double cfrom_type, double arg2, double arg3, double arg4, double arg5, double arg6, double arg7, struct LocalData *Ldata) +{ + int icfrom_type = (int) cfrom_type; + double *C, *D, *L, *R, rtn; // C, D, R - only needed if doing Kinmatics + + C = GetCVarPtr(Ldata); // Only needed if doing Kinmatics + D = GetDVarPtr(Ldata); // Only needed if doing Kinmatics + L = GetLVarPtr(Ldata); // Only needed if using Ldata or Kinmatics + R = GetRVarPtr(Ldata); // Only needed if doing Kinmatics + rtn = -1.0; + return rtn; +} + diff --git a/python/usr_code/usrcode_template.h b/python/usr_code/usrcode_template.h new file mode 100644 index 0000000..fbe2e73 --- /dev/null +++ b/python/usr_code/usrcode_template.h @@ -0,0 +1,134 @@ +#ifdef __KERNEL__ +#include +#else +#define EXPORT_SYMBOL(x) // x +#define KERN_ALERT +#define printk printf +#include +#endif +#include // Global Rt/Gp Externals and structures +#include + +int rtsprintf(char * buf, const char *fmt, ...); + + + +double usr_servo_sample(MotorData *Mptr); +EXPORT_SYMBOL(usr_servo_sample); + +void user_phase_sample( struct MotorData *Mptr); +EXPORT_SYMBOL(user_phase_sample); + +void CaptCompISR(void); +EXPORT_SYMBOL(CaptCompISR); + +double CfromScript(double arg1,double arg2,double arg3,double arg4,double arg5,double arg6,double arg7,struct LocalData *Ldata); +EXPORT_SYMBOL(CfromScript); + +//---------------------------------------- +// Required Kinematic define Names +//---------------------------------------- +#define KinPosMotor L +#define KinVelMotor R +#define KinEnaAxisA 0x1 +#define KinPosAxisA C[0] +#define KinVelAxisA C[32] +#define KinEnaAxisB 0x2 +#define KinPosAxisB C[1] +#define KinVelAxisB C[33] +#define KinEnaAxisC 0x4 +#define KinPosAxisC C[2] +#define KinVelAxisC C[34] +#define KinEnaAxisU 0x8 +#define KinPosAxisU C[3] +#define KinVelAxisU C[35] +#define KinEnaAxisV 0x10 +#define KinPosAxisV C[4] +#define KinVelAxisV C[36] +#define KinEnaAxisW 0x20 +#define KinPosAxisW C[5] +#define KinVelAxisW C[37] +#define KinEnaAxisX 0x40 +#define KinPosAxisX C[6] +#define KinVelAxisX C[38] +#define KinEnaAxisY 0x80 +#define KinPosAxisY C[7] +#define KinVelAxisY C[39] +#define KinEnaAxisZ 0x100 +#define KinPosAxisZ C[8] +#define KinVelAxisZ C[40] +#define KinEnaAxisAA 0x200 +#define KinPosAxisAA C[9] +#define KinVelAxisAA C[41] +#define KinEnaAxisBB 0x400 +#define KinPosAxisBB C[10] +#define KinVelAxisBB C[42] +#define KinEnaAxisCC 0x800 +#define KinPosAxisCC C[11] +#define KinVelAxisCC C[43] +#define KinEnaAxisDD 0x1000 +#define KinPosAxisDD C[12] +#define KinVelAxisDD C[44] +#define KinEnaAxisEE 0x2000 +#define KinPosAxisEE C[13] +#define KinVelAxisEE C[45] +#define KinEnaAxisFF 0x4000 +#define KinPosAxisFF C[14] +#define KinVelAxisFF C[46] +#define KinEnaAxisGG 0x8000 +#define KinPosAxisGG C[15] +#define KinVelAxisGG C[47] +#define KinEnaAxisHH 0x10000 +#define KinPosAxisHH C[16] +#define KinVelAxisHH C[48] +#define KinEnaAxisLL 0x20000 +#define KinPosAxisLL C[17] +#define KinVelAxisLL C[49] +#define KinEnaAxisMM 0x40000 +#define KinPosAxisMM C[18] +#define KinVelAxisMM C[50] +#define KinEnaAxisNN 0x80000 +#define KinPosAxisNN C[19] +#define KinVelAxisNN C[51] +#define KinEnaAxisOO 0x100000 +#define KinPosAxisOO C[20] +#define KinVelAxisOO C[52] +#define KinEnaAxisPP 0x200000 +#define KinPosAxisPP C[21] +#define KinVelAxisPP C[53] +#define KinEnaAxisQQ 0x400000 +#define KinPosAxisQQ C[22] +#define KinVelAxisQQ C[54] +#define KinEnaAxisRR 0x800000 +#define KinPosAxisRR C[23] +#define KinVelAxisRR C[55] +#define KinEnaAxisSS 0x1000000 +#define KinPosAxisSS C[24] +#define KinVelAxisSS C[56] +#define KinEnaAxisTT 0x2000000 +#define KinPosAxisTT C[25] +#define KinVelAxisTT C[57] +#define KinEnaAxisUU 0x4000000 +#define KinPosAxisUU C[26] +#define KinVelAxisUU C[58] +#define KinEnaAxisVV 0x8000000 +#define KinPosAxisVV C[27] +#define KinVelAxisVV C[59] +#define KinEnaAxisWW 0x10000000 +#define KinPosAxisWW C[28] +#define KinVelAxisWW C[60] +#define KinEnaAxisXX 0x20000000 +#define KinPosAxisXX C[29] +#define KinVelAxisXX C[61] +#define KinEnaAxisYY 0x40000000 +#define KinPosAxisYY C[30] +#define KinVelAxisYY C[62] +#define KinEnaAxisZZ 0x80000000 +#define KinPosAxisZZ C[31] +#define KinVelAxisZZ C[63] +#define KinAxisUsed D[0] +#define KinVelEna D[0] +//---------------------------------------- + + +