diff --git a/CMakeLists.txt b/CMakeLists.txt index 46ffa06ab9354d683e7b963fcc45a9e38fb54c4d..a2471062c92e7cfaf4133e0dfc4849cd09aa3d9e 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -161,6 +161,10 @@ IF(BUILD_PYTHON_INTERFACE) DESTINATION ${PYTHON_SITELIB}/${SOTTALOSBALANCE_PYNAME}/talos) IF(BUILD_TEST) INSTALL(FILES python/${SOTTALOSBALANCE_PYNAME}/test/__init__.py + python/${SOTTALOSBALANCE_PYNAME}/test/test_COMTraj_feedback_gazebo.py + python/${SOTTALOSBALANCE_PYNAME}/test/appli_COMTraj_feedback_gazebo.py + python/${SOTTALOSBALANCE_PYNAME}/test/test_COMTraj_sensorfeedback.py + python/${SOTTALOSBALANCE_PYNAME}/test/appli_COMTraj_sensorfeedback.py python/${SOTTALOSBALANCE_PYNAME}/test/test_COMTraj_checkfeedback_gazebo.py python/${SOTTALOSBALANCE_PYNAME}/test/appli_COMTraj_checkfeedback_gazebo.py python/${SOTTALOSBALANCE_PYNAME}/test/test_ffSubscriber.py diff --git a/python/sot_talos_balance/create_entities_utils.py b/python/sot_talos_balance/create_entities_utils.py index 82b8d309e55e766f256085a8afbf1dc3110a995d..129eee73ed543f91f0d934604f3193269256d5fe 100644 --- a/python/sot_talos_balance/create_entities_utils.py +++ b/python/sot_talos_balance/create_entities_utils.py @@ -25,6 +25,7 @@ from sot_talos_balance.utils.filter_utils import create_cheb from sot_talos_balance.utils.sot_utils import Bunch from dynamic_graph import plug +from dynamic_graph.ros import RosPublish N_JOINTS = 32; @@ -102,6 +103,9 @@ def create_device_filters(robot, dt): filters.joints_kin = create_chebi1_checby2_series_filter("joints_kin", dt, N_JOINTS); filters.ft_RF_filter = create_chebi1_checby2_series_filter("ft_RF_filter", dt, 6); filters.ft_LF_filter = create_chebi1_checby2_series_filter("ft_LF_filter", dt, 6); + filters.ft_RH_filter = create_chebi1_checby2_series_filter("ft_RH_filter", dt, 6); + filters.ft_LH_filter = create_chebi1_checby2_series_filter("ft_LH_filter", dt, 6); + filters.torque_filter = create_chebi1_checby2_series_filter("ptorque_filter", dt, N_JOINTS); filters.acc_filter = create_chebi1_checby2_series_filter("acc_filter", dt, 3); filters.gyro_filter = create_chebi1_checby2_series_filter("gyro_filter", dt, 3); filters.estimator_kin = create_chebi1_checby2_series_filter("estimator_kin", dt, N_JOINTS); @@ -109,6 +113,9 @@ def create_device_filters(robot, dt): plug(robot.device.joint_angles, filters.estimator_kin.x); # device.state, device.joint_angles or device.motor_angles ? plug(robot.device.forceRLEG, filters.ft_RF_filter.x); plug(robot.device.forceLLEG, filters.ft_LF_filter.x); + plug(robot.device.forceRARM, filters.ft_RH_filter.x); + plug(robot.device.forceLARM, filters.ft_LH_filter.x); + plug(robot.device.ptorque, filters.torque_filter.x); # switch following lines if willing to use imu offset compensation #~ plug(robot.imu_offset_compensation.accelerometer_out, filters.acc_filter.x); @@ -222,12 +229,13 @@ def addSignalsToTracer(tracer, device, outputs): addTrace(tracer,device,sign); return -def create_tracer(robot,entity,tracer_name, outputs): +def create_tracer(robot,entity,tracer_name, outputs=None): tracer = TracerRealTime(tracer_name) tracer.setBufferSize(80*(2**20)) tracer.open('/tmp','dg_','.dat') robot.device.after.addSignal('{0}.triger'.format(tracer.name)) - addSignalsToTracer(tracer, entity, outputs) + if outputs is not None: + addSignalsToTracer(tracer, entity, outputs) return tracer def reset_tracer(device,tracer): @@ -247,6 +255,21 @@ def dump_tracer(tracer): sleep(0.2); tracer.close(); +def create_rospublish(robot, name): + rospub = RosPublish(name) + robot.device.after.addSignal(rospub.name+'.trigger') + return rospub + +def create_topic(rospub, entity, signalName, robot=None, data_type='vector'): + if not entity.hasSignal(signalName): # check needed to prevent creation of broken topic + raise AttributeError( 'Entity %s does not have signal %s' % (entity.name, signalName) ) + rospub_signalName = '{0}_{1}'.format(entity.name, signalName) + topicname = '/sot/{0}/{1}'.format(entity.name, signalName) + rospub.add(data_type,rospub_signalName,topicname) + plug(entity.signal(signalName), rospub.signal(rospub_signalName)) + if robot is not None: + robot.device.after.addSignal( '{0}.{1}'.format(entity.name, signalName) ) + def create_dummy_dcm_estimator(robot): from math import sqrt estimator = DummyDcmEstimator("dummy") diff --git a/python/sot_talos_balance/meta_task_config.py b/python/sot_talos_balance/meta_task_config.py index d2a25eeaa93f681615b54eb3f1f6c3bfc99c0899..084431914803d95cb393e96a04bbefb459a3b076 100644 --- a/python/sot_talos_balance/meta_task_config.py +++ b/python/sot_talos_balance/meta_task_config.py @@ -1,14 +1,12 @@ from dynamic_graph.sot.core.meta_task_6d import toFlags from dynamic_graph import plug from dynamic_graph.sot.core import * -# from dynamic_graph.sot.core.meta_tasks import setGain -# from dynamic_graph.sot.dyninv import * from dynamic_graph.sot.core.matrix_util import matrixToTuple, vectorToTuple,rotate from numpy import matrix, identity, zeros, eye class MetaTaskConfig(object): - def __init__(self,dyn,config,name="config"): + def __init__(self,dyn,config=None,name="config"): self.dyn=dyn self.name=name self.config = config @@ -18,10 +16,11 @@ class MetaTaskConfig(object): self.gain = GainAdaptive('gain'+name) plug(dyn.position,self.feature.errorIN) - robotDim = len(dyn.position.value) + robotDim = dyn.getDimension() self.feature.jacobianIN.value = matrixToTuple( identity(robotDim) ) self.feature.setReference(self.featureDes.name) - self.feature.selec.value = toFlags(self.config) + if config is not None: + self.feature.selec.value = toFlags(self.config) def plugTask(self): self.task.add(self.feature.name) @@ -37,7 +36,7 @@ class MetaTaskConfig(object): self.featureDes.errorIN.value = v class MetaTaskKineConfig(MetaTaskConfig): - def __init__(self,dyn,config,name="config"): + def __init__(self,dyn,config=None,name="config"): MetaTaskConfig.__init__(self,dyn,config,name) self.task = Task('task'+name) self.plugTask() diff --git a/python/sot_talos_balance/test/appli_COMTraj_feedback_gazebo.py b/python/sot_talos_balance/test/appli_COMTraj_feedback_gazebo.py new file mode 100644 index 0000000000000000000000000000000000000000..a2c2f7cabdd924931bcdb92d407f2a3eab59d3a9 --- /dev/null +++ b/python/sot_talos_balance/test/appli_COMTraj_feedback_gazebo.py @@ -0,0 +1,89 @@ +from sot_talos_balance.create_entities_utils import * +from sot_talos_balance.meta_task_config import MetaTaskKineConfig +from dynamic_graph.sot.core.meta_tasks_kine import MetaTaskKine6d, MetaTaskKineCom, gotoNd +from dynamic_graph import plug +from dynamic_graph.sot.core import SOT +from dynamic_graph.sot.core.operator import Mix_of_vector, Selec_of_vector + +from dynamic_graph.ros import RosSubscribe +from dynamic_graph.sot.dynamics_pinocchio import DynamicPinocchio + +dt = robot.timeStep; + +# --- COM trajectory generator +robot.comTrajGen = create_com_trajectory_generator(dt,robot); + +# --- Subscriber +robot.subscriber = RosSubscribe("base_subscriber") +robot.subscriber.add("vector","position","/sot/base_link/position") +robot.subscriber.add("vector","velocity","/sot/base_link/velocity") + +# --- Merger +robot.stateselec = Selec_of_vector("stateselec") +robot.stateselec.selec(6,robot.dynamic.getDimension()) +plug(robot.device.robotState,robot.stateselec.sin) + +robot.stateselec = Selec_of_vector("stateselec") +robot.stateselec.selec(6,robot.dynamic.getDimension()) +plug(robot.device.robotState,robot.stateselec.sin) + +robot.statemix = Mix_of_vector("statemix") + +robot.statemix.setSignalNumber(3) + +robot.statemix.addSelec(1,0,6) +robot.statemix.addSelec(2,6,robot.dynamic.getDimension()-6) + +robot.statemix.default.value=[0.0]*robot.dynamic.getDimension() +plug(robot.subscriber.position,robot.statemix.signal("sin1")) +plug(robot.stateselec.sout,robot.statemix.signal("sin2")) + +# --- Dynamic pinocchio +robot.rdynamic = DynamicPinocchio("real_dynamics") +robot.rdynamic.setModel(robot.dynamic.model) +robot.rdynamic.setData(robot.rdynamic.model.createData()) + +plug(robot.device.robotState,robot.rdynamic.position) +plug(robot.subscriber.position,robot.rdynamic.ffposition) + +plug(robot.device.robotVelocity,robot.rdynamic.velocity) +plug(robot.subscriber.velocity,robot.rdynamic.ffvelocity) + +robot.rdynamic.acceleration.value = [0.0]*robot.dynamic.getDimension() + +# --- Posture +robot.taskPos = MetaTaskKineConfig(robot.rdynamic) +robot.taskPos.featureDes.errorIN.value = robot.dynamic.position.value +robot.taskPos.task.controlGain.value = 10 +plug(robot.statemix.sout,robot.taskPos.feature.errorIN) + +# --- COM +robot.taskCom = MetaTaskKineCom(robot.rdynamic) +robot.dynamic.com.recompute(0) +robot.taskCom.featureDes.errorIN.value = robot.dynamic.com.value +robot.taskCom.task.controlGain.value = 10 +plug(robot.comTrajGen.x, robot.taskCom.featureDes.errorIN) + +# --- CONTACTS +#define contactLF and contactRF +robot.contactLF = MetaTaskKine6d('contactLF',robot.rdynamic,'LF',robot.OperationalPointsMap['left-ankle']) +robot.contactLF.feature.frame('desired') +robot.contactLF.gain.setConstant(100) +# robot.contactLF.keep() +locals()['contactLF'] = robot.contactLF + +robot.contactRF = MetaTaskKine6d('contactRF',robot.rdynamic,'RF',robot.OperationalPointsMap['right-ankle']) +robot.contactRF.feature.frame('desired') +robot.contactRF.gain.setConstant(100) +# robot.contactRF.keep() +locals()['contactRF'] = robot.contactRF + +# --- SOLVER +robot.sot = SOT('sot') +robot.sot.setSize(robot.dynamic.getDimension()) +robot.sot.push(robot.contactRF.task.name) +robot.sot.push(robot.contactLF.task.name) +robot.sot.push(robot.taskCom.task.name) +robot.sot.push(robot.taskPos.task.name) + +robot.device.control.value = [0.0]*robot.dynamic.getDimension() diff --git a/python/sot_talos_balance/test/appli_COMTraj_sensorfeedback.py b/python/sot_talos_balance/test/appli_COMTraj_sensorfeedback.py new file mode 100644 index 0000000000000000000000000000000000000000..07cd08eee1dead53b28ff0a9404c7eea0782508c --- /dev/null +++ b/python/sot_talos_balance/test/appli_COMTraj_sensorfeedback.py @@ -0,0 +1,71 @@ +from sot_talos_balance.create_entities_utils import * +from sot_talos_balance.meta_task_config import MetaTaskKineConfig +import sot_talos_balance.control_manager_conf as param_server_conf +from sot_talos_balance.talos import base_estimator_conf +from dynamic_graph.sot.core.meta_tasks_kine import MetaTaskKine6d, MetaTaskKineCom, gotoNd +from dynamic_graph import plug +from dynamic_graph.sot.core import SOT + +from dynamic_graph.sot.dynamics_pinocchio import DynamicPinocchio + +dt = robot.timeStep; + +# --- COM trajectory generator +robot.comTrajGen = create_com_trajectory_generator(dt,robot); + +# --- Estimators +robot.param_server = create_parameter_server(param_server_conf,dt) +robot.device_filters = create_device_filters(robot, dt) +robot.imu_filters = create_imu_filters(robot, dt) +robot.base_estimator = create_base_estimator(robot, dt, base_estimator_conf) +robot.be_filters = create_be_filters(robot, dt) +robot.dcm_estimator = create_dcm_estimator(robot, dt) + +# --- Dynamic pinocchio +robot.rdynamic = DynamicPinocchio("real_dynamics") +robot.rdynamic.setModel(robot.dynamic.model) +robot.rdynamic.setData(robot.rdynamic.model.createData()) + +plug(robot.base_estimator.q,robot.rdynamic.position) + +robot.rdynamic.velocity.value = [0.0]*robot.dynamic.getDimension() + +robot.rdynamic.acceleration.value = [0.0]*robot.dynamic.getDimension() + +# --- Posture +robot.taskPos = MetaTaskKineConfig(robot.rdynamic) +robot.taskPos.featureDes.errorIN.value = robot.dynamic.position.value +robot.taskPos.task.controlGain.value = 10 +plug(robot.base_estimator.q,robot.taskPos.feature.errorIN) + +# --- COM +robot.taskCom = MetaTaskKineCom(robot.rdynamic) +robot.dynamic.com.recompute(0) +robot.taskCom.featureDes.errorIN.value = robot.dynamic.com.value +robot.taskCom.task.controlGain.value = 10 +plug(robot.dcm_estimator.c, robot.taskCom.feature.errorIN) +plug(robot.comTrajGen.x, robot.taskCom.featureDes.errorIN) + +# --- CONTACTS +#define contactLF and contactRF +robot.contactLF = MetaTaskKine6d('contactLF',robot.rdynamic,'LF',robot.OperationalPointsMap['left-ankle']) +robot.contactLF.feature.frame('desired') +robot.contactLF.gain.setConstant(100) +# robot.contactLF.keep() +locals()['contactLF'] = robot.contactLF + +robot.contactRF = MetaTaskKine6d('contactRF',robot.rdynamic,'RF',robot.OperationalPointsMap['right-ankle']) +robot.contactRF.feature.frame('desired') +robot.contactRF.gain.setConstant(100) +# robot.contactRF.keep() +locals()['contactRF'] = robot.contactRF + +# --- SOLVER +robot.sot = SOT('sot') +robot.sot.setSize(robot.dynamic.getDimension()) +robot.sot.push(robot.contactRF.task.name) +robot.sot.push(robot.contactLF.task.name) +robot.sot.push(robot.taskCom.task.name) +robot.sot.push(robot.taskPos.task.name) + +robot.device.control.value = [0.0]*robot.dynamic.getDimension() diff --git a/python/sot_talos_balance/test/test_COMTraj_feedback_gazebo.py b/python/sot_talos_balance/test/test_COMTraj_feedback_gazebo.py new file mode 100644 index 0000000000000000000000000000000000000000..f07e48b2bd515c7a2c7c1624985df244b10da1fc --- /dev/null +++ b/python/sot_talos_balance/test/test_COMTraj_feedback_gazebo.py @@ -0,0 +1,30 @@ +from sot_talos_balance.utils.run_test_utils import run_test, runCommandClient, evalCommandClient +from sot_talos_balance.utils.gazebo_utils import GazeboLinkStatePublisher +from time import sleep + +pub = GazeboLinkStatePublisher('base_link',1000) +print("Starting Gazebo link state publisher...") +pub.start() +print("Gazebo link state publisher started") +raw_input("Wait before running the test") + +run_test('appli_COMTraj_feedback_gazebo.py') + +# wait for sensor values to be ready +sleep(evalCommandClient('robot.timeStep')) + +# set initial conditions from sensor readings +runCommandClient('robot.rdynamic.com.recompute(0)') +runCommandClient('robot.comTrajGen.initial_value.value = robot.rdynamic.com.value') +runCommandClient('robot.contactLF.keep()') +runCommandClient('robot.contactRF.keep()') + +# plug the SOT +runCommandClient('plug(robot.sot.control,robot.device.control)') + +# execute rest of the commands +sleep(2.0) +runCommandClient('robot.comTrajGen.move(1,-0.025,4.0)') +sleep(5.0) +runCommandClient('robot.comTrajGen.startSinusoid(1,0.05,8.0)') + diff --git a/python/sot_talos_balance/test/test_COMTraj_sensorfeedback.py b/python/sot_talos_balance/test/test_COMTraj_sensorfeedback.py new file mode 100644 index 0000000000000000000000000000000000000000..92f76dff652afe3538bebd6d8eaf83df0e687637 --- /dev/null +++ b/python/sot_talos_balance/test/test_COMTraj_sensorfeedback.py @@ -0,0 +1,23 @@ +from sot_talos_balance.utils.run_test_utils import run_test, runCommandClient, evalCommandClient +from time import sleep + +run_test('appli_COMTraj_sensorfeedback.py') + +# wait for sensor values to be ready +sleep(evalCommandClient('robot.timeStep')) + +# set initial conditions from sensor readings +runCommandClient('robot.dcm_estimator.c.recompute(0)') +runCommandClient('robot.comTrajGen.initial_value.value = robot.dcm_estimator.c.value') +runCommandClient('robot.contactLF.keep()') +runCommandClient('robot.contactRF.keep()') + +# plug the SOT +runCommandClient('plug(robot.sot.control,robot.device.control)') + +# execute rest of the commands +sleep(2.0) +runCommandClient('robot.comTrajGen.move(1,-0.025,4.0)') +sleep(5.0) +runCommandClient('robot.comTrajGen.startSinusoid(1,0.05,8.0)') + diff --git a/python/sot_talos_balance/utils/filter_utils.py b/python/sot_talos_balance/utils/filter_utils.py index c5ce73d22b753bc295a81292220fe293b685a58b..a50a0396aa05622f2728b58f60a47e30e84c6aaf 100644 --- a/python/sot_talos_balance/utils/filter_utils.py +++ b/python/sot_talos_balance/utils/filter_utils.py @@ -11,4 +11,22 @@ def create_chebi1_checby2_series_filter(name, dt, size): (1.,-5.32595322,11.89749109,-14.26803139, 9.68705647, -3.52968633, 0.53914042)) return lp_filter; +def create_butter_lp_filter_Wn_04_N_2(name, dt, size): + # (b,a) = butter(N=2, Wn=0.04) + lp_filter = FilterDifferentiator(name) + lp_filter.init(dt, size, + (0.0036216815, 0.007243363, 0.0036216815), + ( 1., -1.8226949252, 0.8371816513)) + + return lp_filter + +def create_bessel_lp_filter_Wn_04_N_2(name, dt, size): + # (b,a) = bessel(N=2, Wn=0.04) + lp_filter = FilterDifferentiator(name) + + lp_filter.init(dt, size, + (0.0035566088, 0.0071132175, 0.0035566088), + ( 1., -1.7899455543, 0.8041719893)) + + return lp_filter