Commit de3e3585 by raphael.deimel

Promote API9 to be the default implementation

parents 9f625c6c 8488e3fc
= Installation Instructions
#Installation Instructions
== Compilation
##Compilation
For compiling, simply use:
make
== Installation
For installing, use:
make install
##Airserver Installation
For installing on a systemd based system, use:
make install_systemd
For older upstart-based Ubuntu's use:
make install_upstart
It will ask you for sudo as the executable needs to be made SUID root.
Also, you need to change the Devicetree overlays of BBB. In /boot/uEnv.txt, disable loading the HDMI overlays:
##Installing from scratch
Please read the file files/startup.sh
###Automatic Startup
The folder files/etc contains boot scripts for both systemd and upstart, copy them into /etc accordingly.
##Necessary Hardware reconfigurations
You need to change the Devicetree overlays of the BBB. In /boot/uEnv.txt, disable loading the HDMI overlays:
##Disable HDMI
optargs=capemgr.disable_partno=BB-BONELT-HDMI,BB-BONELT-HDMIN
==
Call airserver
== Build Dependencies:
##Build Dependencies:
* apt-get install libboost-system-dev
* g++ version>4.6
== Change to g++-4.7 on Debian 7:
##Change to g++-4.7 on Debian 7:
sudo update-alternatives --remove-all g++
sudo apt-get install g++-4.7
......@@ -36,7 +49,7 @@ Call airserver
sudo update-alternatives --install /usr/bin/gcc gcc /usr/bin/gcc-4.7 40 --slave /usr/bin/g++ g++ /usr/bin/g++-4.7
sudo update-alternatives --config gcc #select 4.7 as default
==ADC Bias Calibration
##ADC Bias Calibration
The airserver reports the raw adc values on startup. To calibrate the ADC, copy the values as a space separated list of integers into:
......
===How to add a new controller in the Server
* In src/control.hpp: Subclass the Cntrl() class
* In src/control.hpp: Subclass the Cntrl() class. Have a look at the other subclasses for reference.
* In include/pneumaticbox.h: Define a configuration message in the pneumaticbox API to configure the controller in pneumaticbox.h.
* In include/pneumaticbox.h: Extend getMessageTypeLength() to report the lenght of the new configuration message correctly
* In include/pneumaticbox.h: Define an id for the new configuration message type and also extend getMessageTypeLength() to report the lenght of the new configuration message correctly
* In src/main.cpp: add the instantation of the controller when receiving the configuration message by adding a case in the big switch statement of the main loop
* Create a new file controller\_xxx.cpp which will contain the implementation of the new controller class.
* in makefile: Add a new file controller\_xxx.cpp to the SOURCES\_CONTROLLER variable
* In src/controller_xxx.cpp: Implement your controller here. Have a look at other controller\_yyy.cpp files for guidance
* In include/pneumaticbox.h: When done: Bump the API version in pneumaticbox.h and indicate backwards compatibility in IsClientCompatible() (you only extended the API)
......
......@@ -17,7 +17,7 @@
# otherwise the system hangs for tens of milliseconds
#
# kernel 4.1 works with 9MBit, 3.14 is slower.
cho "179:0 5000000" > /sys/fs/cgroup/blkio/blkio.throttle.write_bps_device
echo "179:0 5000000" > /sys/fs/cgroup/blkio/blkio.throttle.write_bps_device
exit 0
../../../lib/airserver/airserver.service
\ No newline at end of file
[Unit]
Description=RBOLab's Airserver for Pneumaticbox hardware
#After=syslog.target
[Service]
Type=simple
ExecStart=/usr/local/bin/airserver
[Install]
WantedBy=multi-user.target
#!/bin/bash
# This file contains the commands required to setup airserver on an unmodified official Beaglebone Debain 8.2 image
#
#
exit 0 #to catch stupid people
#this can also be done with the rename.sh script:
echo "beagle123" > /etc/hostname
echo "127.0.0.1 beagle123" >> /etc/hosts
sudo useradd rbolab -m --password 'robo0909*'
sudo adduser rbolab adm
sudo adduser rbolab sudo
sudo adduser rbolab kmem
sudo adduser rbolab dialout
sudo adduser rbolab video
sudo adduser rbolab plugdev
sudo adduser rbolab users
sudo adduser rbolab netdev
sudo adduser rbolab i2c
sudo adduser rbolab spi
sudo adduser rbolab systemd-journal
sudo adduser rbolab weston-launch
sudo adduser rbolab xenomai
#NOW reboot and reconnect as rbolab user
#create local ssh keys for git
ssh-keygen
#packages to install:
sudo apt-get update
#essentials:
sudo apt-get install build-essential libboost-all-dev device-tree-compiler schedtool screen chrony cgroup-tools
#PRU tools: library to load PRU code and cross-compiler
sudo apt-get install am335x-pru-package ti-pru-cgt-installer
#nice to haves:
sudo apt-get install python-scipy ipython python-qt4
#configure the time server
echo "server 192.168.0.1" >> /etc/chrony/chrony.conf
#
#
# first check which kernel is installed with
uname -a
#and add the -rt- infix. example:
sudo apt-get install linux-image-4.3.3-bone16
#now reboot. It is needed for the next step!
mkdir git; cd git
#install ROS indigo:
sudo sh -c 'echo "deb http://packages.ros.org/ros/ubuntu trusty main" > /etc/apt/sources.list.d/ros-latest.list'
wget https://raw.githubusercontent.com/ros/rosdistro/master/ros.key -O - | sudo apt-key add -
sudo apt-get update
sudo apt-get install ros-indigo-ros-base
#setup the account for ROS:
echo "source /opt/ros/indigo/setup.sh" >> ~/.bashrc
#
# Install the airserver
#clone git repositories:
git clone https://gitlab.tubit.tu-berlin.de/rbo-lab/pneumaticbox-airserver.git
#configure the push to go via ssh authentication:
#git remote set-url --push origin git@gitlab.tubit.tu-berlin.de:rbo-lab/pneumaticbox-airserver.git
#
# clone Robert Nelsons devicetree rebuilder repository
#
# we want the am335x-boneblack-emmc-overlay.dtb devicetree file which includes emmc but no hdmi configuration, leaving those pins in default gpio mode
#
# make sure you select the correct branch according to the kernel running:
git clone -b 4.1.x https://github.com/RobertCNelson/dtb-rebuilder.git
cd dtb-rebuilder
#
# compile devicetree blobs and install them into /boot/dtbs:
make && sudo make install
cd ..
#
# set the devicetree blob to use when booting. Make sure that is correct or you have to reflash
#
#for simplicity: copy the whole boot settings:
sudo cp /boot/uEnv.txt /boot/uEnv.txt.dist
sudo cp pneumaticbox-airserver/files/boot/uEnv.txt /boot/uEnv.txt
# Install config-pin utility, which helps to reconfigure/test gpio config
#
git clone https://github.com/cdsteinkuehler/beaglebone-universal-io.git
#install the python client library:
git clone https://gitlab.tubit.tu-berlin.de/rbo-lab/python-pneumaticbox.git
cd python-pneumaticbox
sudo python setup.py install
cd git/airserver
make && sudo make install
#install upstart scripts to start the airserver automatically (for ubuntu < 15.04)
cp files/etc/init/* /etc/init
#TODO: configure sudoers to allow boot/halt/reboot and starting/stoping airserver
sudo reboot
# How to avoid setting up from scratch:
# Insert a Micro-SD (>=4GB) and call this script:
# (only on Robert C.Nelsons distribution image)
sudo /opt/scripts/tools/eMMC/beaglebone-black-make-microSD-flasher-from-eMMC.sh
......@@ -17,7 +17,7 @@ INCLUDES= -I ../include -I $(BBBIO_INC)
#LDFLAGS= -lBBBio -lm -pthread -lboost_filesystem -lboost_system
LDFLAGS= -L $(BBBIO_LIB)
LDLIBS= -lBBBio -lm -lrt
SOURCES_CONTROLLER = controller_watchdog_pressure.cpp controller_threshold.cpp controller_pressurelimiter.cpp controller_bangbang.cpp #controller_pwm.cpp controller_pressure.cpp
SOURCES_CONTROLLER = controller_watchdog_pressure.cpp controller_threshold.cpp controller_pressurelimiter.cpp controller_bangbang.cpp controller_mass.cpp #controller_pwm.cpp controller_pressure.cpp
SOURCES_SENSORS = i2csensor_ad7147.cpp #i2csensor_ads1115.cpp
SOURCES=main.cpp sen_akt.cpp server.cpp data_handling.cpp controller.cpp $(SOURCES_CONTROLLER) $(SOURCES_SENSORS)
SOURCEDIR=../src
......@@ -50,10 +50,24 @@ $(EXEC): $(OBJECTS) $(BBBIO_LIB)/libBBBio.a $(GLOBALDEPS)
clean:
rm -r ./$(BUILDDIR)/*
install: all
install: all install_upstart
install_systemconfigurationfiles:
sudo cp -r files/etc/ /etc/
install_upstart:
sudo stop airserver 2>/dev/null; true
sudo chown root:root $(BUILDDIR)/$(EXEC)
sudo chmod u+s $(BUILDDIR)/$(EXEC)
sudo cp $(BUILDDIR)/$(EXEC) /usr/local/bin
sudo start airserver ; true
install_systemd:
sudo systemctl stop airserver.service
sudo chown root:root $(BUILDDIR)/$(EXEC)
sudo chmod u+s $(BUILDDIR)/$(EXEC)
sudo cp $(BUILDDIR)/$(EXEC) /usr/local/bin
sudo systemctl start airserver.service
......@@ -108,6 +108,78 @@ namespace AirserverController{
AirServerSignalValue level_off;
AirServerSignalValue level_deflate;
};
/**
* Mass controller
*/
class CntrlMass : public Cntrl{
private:
MsgConfigurationControllerMass config; //copy of the configuration
AirServerSignalValue out_inflation_valvestate; //local copy of the last set valve state for graceful degradation when not controlling valves
AirServerSignalValue out_deflation_valvestate; //local copy of the last set valve state for graceful degradation when not controlling valves
AirServerSignalValue desired_mass; //current desired mass, either computed from desired massflow or set from a signal
//internal states of the mass observer:
AirServerSignalValue observer_mass_estimate; //aggregate estimate
AirServerSignalValue observer_term_injector; //injector model
AirServerSignalValue observer_term_friction; //friction model
// nominal ambient pressure used as pressure reference and outlet pressure when deflating:
float P_ENV= 101.3; //kPa
// error between mass desired
// and current in-/deflated mass
float error;
/** calculates massflow using a linear model
* @param Pi: inlet pressure as measured, relative to environment, not absolute
* for inflation pressure_supply, for deflation pressure_out
* @param Po: outlet pressure as measured, relative to environment, not absolute
* for inflation pressure_out, for deflation 0.0
* @param scale: a teached scaling factor
*
* @return mass flow according to linear model
*
*/
float MFLinearModel(float Pi, float Po, float scale= 1.0);
/** calculates massflow using a nonlinear model as provided by Lee Company
* @param Pi: inlet pressure as measured, relative to environment, not absolute
* always greater than zero
* for inflation pressure_supply, for deflation pressure_out
* @param Po: outlet pressure as measured, relative to environment, not absolute,
* for inflation pressure_out, for deflation 0.0
* @param scale: a teached scaling factor
*
* @return mass flow according to linear model
*
*/
float MFLeeCompanyModel(float Pi, float Po, float scale= 1.0);
/** calculates massflow to a nonlinear model using a flow equation
* @param Pi: inlet pressure as measured, relative to environment, not absolute
* always greater than zero
* for inflation pressure_supply, for deflation pressure_out
* @param Po: outlet pressure as measured, relative to environment, not absolute
* for inflation pressure_out, for deflation 0.0
* @param scale: a teached scaling factor
*
* @return mass flow according to linear model
*
*/
float MFPSIModel(float Pi, float Po, float scale= 1.0);
public:
CntrlMass() : Cntrl(){}
CntrlMass(MsgConfigurationControllerMass *conf);
int run();
};
/**
* Controller monitoring the pressure sensor and sending emergency events
......
/*
* Mass flow controller: actuate channel according to a signal:
*
*
* Author: Raphael
*/
#include "global.hpp"
#include "controller.hpp"
#include <iostream>
#include <math.h>
namespace AirserverController{
CntrlMass::CntrlMass(MsgConfigurationControllerMass *conf)
{
//std::cout << "configuring mass controller" << std::endl;
id = conf->header_config.id;
config = *conf; //copy everything
this->error= 0.0;
desired_mass = 0.0;
SetData( config.out_massobserver_term_friction, 0.0 );
SetData( config.out_massobserver_term_injector, 0.0 );
SetData( config.out_massobserver, 0.0 );
// std::cout <<"[MASS CTRL] Coeff: " << std::endl
// <<" inflation path: " << config.c_inflate
// << ", " << config.c_inflate_friction << ", "
// << config.c_inflate_injector << ", " << config.c_inflate_Psupply << ", "
// << config.c_inflate_Pout << std::endl;
// std::cout <<" deflation path: " << config.c_deflate
// << ", " << config.c_deflate_friction << ", "
// << config.c_deflate_injector << ", " << config.c_deflate_Psupply << ", "
// << config.c_deflate_Pout << std::endl;
// std::cout <<" inflation threshold: " << config.c_inflation_threshold << std::endl;
// std::cout <<" deflation threshold: " << config.c_deflation_threshold << std::endl;
}
float CntrlMass::MFLinearModel(float Pi, float Po, float scale) {
float dp= (Pi - Po);
float mf= scale * dp;
return mf;
}
float CntrlMass::MFLeeCompanyModel(float Pi, float Po, float scale) {
// absolute pressure ratio
float ratio= Pi/Po;
float mf= 0.0;
float dp= (Pi - Po);
if (dp < 0.0) {dp = 0.0;} //to avoid strange behavior
if(ratio >= 1.9) { // sonic
mf= scale * Pi;
}else{ //subsonic
mf= 2 * scale * sqrt(dp*Po);
}
return mf;
// scaling factor includes:
// non linear model: (injector equation)
// R= 2 K f_t sqrt(dP P_1) / Q
// constants K and f_t depending on units
// for flow Q and temperature T
// for Q in kg/60s: K = 0.0481
// for T= 20deg Celsius: f_t= 1
// P1: absolute pressure in front of resistor
// P2: absolute pressure behind resistor
// P2= pressure_out + pressure environment
// dP= P1 - P2
// Q= massflow [kg/s]= 2 * 0.0481 * 1 * sqrt(dP*P_2)/ R*60
}
float CntrlMass::MFPSIModel(float Pi, float Po, float scale) {
float ratio= Po/Pi;
// The ratio of specific heats at constant pressure
// and constant volume, c_p / c_vv
float gamma = 1.4; // for dry air
float critical_pressure_ratio= pow(2.0/(gamma+1.0), gamma/(gamma-1.0));
//std::cout << "[MASSFLOW CONTROLLER] critical pressure ratio: "
// << critical_pressure_ratio << std::endl;
float mf= 0.0;
if(ratio > 0.999) {
// This should actually never happen for the soft actuator.
// For inflation supply pressure would reach channel pressure.
// For deflation, assuming an abbsolute supply pressure near 300kPa+103kPa,
// the measured channel pressure would need to be 0.103 kPa.
// That equals a complete deflation that can be "manually" handeld
// on the client side, knowing that the channel pressure will be Zero.
//std::cout << "[MASSFLOW CONTROLLER] PSI Model: inlet pressure ("
// << Pi << ") equals outlet pressure ("<< Po
// << "). Massflow= zero." << std::endl;
} else {
if(ratio >= critical_pressure_ratio) {
// 0.528 < ratio < 0.999
mf= scale * Pi * sqrt(2.0/ (gamma-1.0) ) * sqrt(pow(ratio,(2.0/gamma)) - pow(ratio,(gamma+1.0/gamma)) );
} else {
// ratio < 0.528
mf= scale * Pi * sqrt( pow(critical_pressure_ratio,(gamma+1.0)/gamma) );
}
}// ratio > 0.999
return mf;
}
int CntrlMass::run() {
if (gotDeactivated) { //on deactivation, make sure no valves stay open:
out_inflation_valvestate = 0.0;
out_deflation_valvestate = 0.0;
SetData(config.out_inflate, out_inflation_valvestate);
SetData(config.out_deflate, out_deflation_valvestate);
}
if(!activated){
//reset all internal states:
this->error= 0.0;
desired_mass = 0.0;
observer_term_friction = 0.0;
observer_term_injector = 0.0;
observer_mass_estimate = 0.0;
// export internal states to signals for monitoring purposes:
SetData( config.out_massobserver_term_friction, observer_term_friction );
SetData( config.out_massobserver_term_injector, observer_term_injector );
SetData( config.out_massobserver, observer_mass_estimate );
return EXIT_SUCCESS;
}
//compute the absolute pressures:
float p_supply = P_ENV + GetData(config.pressure_supply);
float p_out = P_ENV + GetData(config.pressure_out);
// I N I T V A R I A B L E S
// current massflow for multiple models
float mf_curr_friction = 0.0;
float mf_curr_leeco = 0.0;
// error can change in each step
float last_step_error= this->error;
// M A S S F L O W
// calculate current massflow
// I N F L A T I O N
if( GetData(config.out_inflate) == 1.0 ) {
// compute current mass flow
mf_curr_friction= MFLinearModel( p_supply, p_out, config.c_inflate_friction);
mf_curr_leeco = MFLeeCompanyModel( p_supply, p_out, config.c_inflate_injector);
}
// D E F L A T I O N
if( GetData(config.out_deflate) == 1.0 ) {
// pressure out = ambient pressure
mf_curr_friction= MFLinearModel( p_out, P_ENV, config.c_deflate_friction);
mf_curr_leeco = MFLeeCompanyModel( p_out, P_ENV, config.c_deflate_injector);
}
//compute the mass change in the last timestep given the flow estimate:
float delta_mass_friction= mf_curr_friction* PERIOD_S;
float delta_mass_leeco = mf_curr_leeco * PERIOD_S;
// update mass estimate
observer_term_friction += delta_mass_friction;
observer_term_injector += delta_mass_leeco;
observer_mass_estimate = observer_mass_estimate + delta_mass_friction + delta_mass_leeco; // combine models
// export internal states to signals for monitoring purposes:
SetData( config.out_massobserver_term_friction, observer_term_friction );
SetData( config.out_massobserver_term_injector, observer_term_injector );
SetData( config.out_massobserver, observer_mass_estimate );
//Compute the current desired mass from either desired massflow or just use a user-supplied value:
if (config.in_desired_massflow != SIGNAL_NONE) {
desired_mass += GetData(config.in_desired_massflow) * PERIOD_S;
} else if (config.in_desired_mass != SIGNAL_NONE) {
desired_mass = GetData(config.in_desired_mass); //else just get value from a signal
} else {
desired_mass = 0.;
}
// E V A L U A T E E R R O R
// calculate current error:
this->error= desired_mass - observer_mass_estimate;
// stop in-/deflating when error is zero
// that means, when it switched its sign
// since last time step
if(last_step_error*this->error < 0) { //if error sign changes
out_inflation_valvestate = 0.0;
out_deflation_valvestate = 0.0;
SetData(config.out_inflate, out_inflation_valvestate);
SetData(config.out_deflate, out_deflation_valvestate);
}
if( (this->error <= config.c_inflation_threshold) && (this->error >= config.c_deflation_threshold) ) {// I N S I D E T O L E R A N C E S
} else { // O U T S I D E T O L E R A N C E S
if( this->error > 0 ) { // mass is lower than desired -> start to inflate
if (config.out_inflate != SIGNAL_NONE) {
out_inflation_valvestate = GetData(config.out_inflate); //make sure to use real out state
}
if(out_inflation_valvestate < 0.5) {
// Add constant inflation error at inflation start
float mass_bias = config.c_inflate;
mass_bias += p_supply * config.c_inflate_Psupply;
mass_bias += p_out * config.c_inflate_Pout;
observer_mass_estimate += mass_bias;
}
out_inflation_valvestate = 1.0;
out_deflation_valvestate = 0.0;
} else {// mass higher than desired -> start to deflate
if (config.out_deflate != SIGNAL_NONE) {
out_deflation_valvestate = GetData(config.out_deflate); //make sure to use real out state
}
// add constants deflation model when deflation starts
if(out_deflation_valvestate < 0.5) {
float mass_bias = config.c_deflate;
mass_bias += p_supply * config.c_deflate_Psupply;
mass_bias += p_out * config.c_deflate_Pout;
observer_mass_estimate += mass_bias;
}
out_inflation_valvestate = 0.0;
out_deflation_valvestate = 1.0;
} // error in-/outside tolerance checking
SetData(config.out_inflate, out_inflation_valvestate);
SetData(config.out_deflate, out_deflation_valvestate);
} // error threshold checking
SetData( config.out_massobserver_term_friction, observer_term_friction );
SetData( config.out_massobserver_term_injector, observer_term_injector );
SetData( config.out_massobserver, observer_mass_estimate );
return EXIT_SUCCESS;
} // run()
} //namespace
......@@ -199,12 +199,10 @@ int main(int argc, char** argv){
#endif
//Check if we need to skip some iterations because we are too late already
if (next_update < end) {
uint32_t i=0;
while (next_update < end) {
next_update = next_update + RT_PERIOD; //fast-forward and skip iterations
i++;
}
std::cout << "Info: Loop took too long! (" << usecs<<"us). Skipping control loop "<< i <<" times."<<std::endl;
std::cout << "Info: Loop took too long! (" << usecs<<"us). Skipping to next possible control loop timepoint."<<std::endl;
next_update = end;
next_update.nsecs = next_update.nsecs + (AirserverController::PERIOD_NS - next_update.nsecs % AirserverController::PERIOD_NS); //align to the next timepoint
next_update = next_update + RT_PERIOD; //fast-forward and skip one iteration
}
Sleep(next_update - end); //wait until the next loop iteration should start
......@@ -277,6 +275,10 @@ int main(int argc, char** argv){
new_component = (AirserverController::Cntrl*) new AirserverController::CntrlBangBang((MsgConfigurationControllerBangBang*)d);
controllers->add(new_component);
break;
case MSGTYPE_CONFIG_CONTROLLER_MASS:
new_component = (AirserverController::Cntrl*) new AirserverController::CntrlMass((MsgConfigurationControllerMass*)d);
controllers->add(new_component);
break;
case MSGTYPE_CONFIG_CONTROLLER_WATCHDOG_PRESSURE:
new_component = new AirserverController::CntrlPressureWatchdog((MsgConfigurationWatchdogPressure*)d);
controllers->add(new_component);
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment