AutoPosition + Mocap-UpperBody

Hello,

I am trying using MotionCap from Vicon C3D in AnyBody for an UpperLimb Model. My goal actually is to auto position and auto scale from the c3d data. Autoposition is working, I modified your AutoPelvPos function for my need, so it can function with different c3d files. My model have 4 markers on thorax, 3 on shoulder,
6 on humeral, 2 on elbow, 2 on ulna, 2 on radius, 2 on wrist, 3 on hand
Like in this topic UpperLimb MoCap I used softdrivers to run my models. And disabled the drivers for segments I have markers on.

// Softdrivers fuer Segmente (Pelvis, Kopf), die keine Marker besitzen
#define BM_MANNEQUIN_DRIVER_DEFAULT ON
  // Oberarm
  #define BM_MANNEQUIN_DRIVER_GLENOHUMERAL_ABDUCTION_RIGHT OFF
  #define BM_MANNEQUIN_DRIVER_GLENOHUMERAL_FLEXION_RIGHT OFF
  #define BM_MANNEQUIN_DRIVER_GLENOHUMERAL_EXTERNAL_ROTATION_RIGHT OFF
  // Ellbogengelenk
  #define BM_MANNEQUIN_DRIVER_ELBOW_FLEXION_RIGHT OFF
  #define BM_MANNEQUIN_DRIVER_ELBOW_PRONATION_RIGHT OFF
  // Handgelenk
  #define BM_MANNEQUIN_DRIVER_WRIST_FLEXION_RIGHT OFF
  #define BM_MANNEQUIN_DRIVER_WRIST_ABDUCTION_RIGHT OFF
  #define BM_MANNEQUIN_DRIVER_HAND_RIGHT OFF

Its working but right now is that the pelvis and thorax are slightly rotating when i run analysis. It seems I am missing some drivers for that. I tried to fixed it to a ground point, but that would only worked with some of the c3d files.
For scaling I read your tutorial and it seems I cant use SCALING_XYZ because I don't have lower body (foot) and it have (in the new repository) dependency to scaling. I have the mass and height and the c3d markers. I use SCALING_LENGTHMASS instead.
I activated ConstructModelOnOff = On; to have the scaling with the c3d. If I change the mass it change the scaling too, but if I change the height nothing happens. Is it because I use SCALING_LENGTHMASS? Would you recommend another scaling system?

And I have another 2 questions:

  • Is it possible to create an IF-function to switch between left and right handed people with the same model? i have some c3d with right and with left handed persons. Or is it better to do 2 AnyBody models for left and right handed persons?
  • I read about using python with AnyBody. Is it possible to program an UI for loading the c3d model and giving out the diagrams for joint angle and show the model view too? I am not sure how good the framework from AnyBody for python is. It is just a thought myself.

I would like to upload my model, but it seems I can't because I am a new member.

Thank you in advance and greetings
Irzigen

Hi Irzigen,

Here are some answers,

As i understand the marker configuration you have no makers from thorax and below.

In this case please ensure that the PelvisPos XYZ PelvisRot XYZ are all off, but you already did this as far as i understand. Please also ensure that PelvisThorax DOF are ON.

I would disable the legs from the model sinse you have no markers for this, see the AMMR documentation on how to do this https://anyscript.org/ammr-doc/bm_config/index.html

I do not see why XYZ scaling should not work, but you will not be able to optimize trunkheight due to missing markers so this you have to disable in the labspecific.any file.

You can use define statements in such situation.

#define RightHanded

#ifdef RightHanded

//Define you right hand markers here
#endif


#ifdef LeftHanded

//Define you left hand markers here
#endif

The python hook can be used to send information to python from AnyBody and then receive the data again. So if you are missing mathematical functionality in the script you can use python as a function call, the ModelView can not be displayed in python. AnyBody will automatically ensure the functions is called when it is needed depending on the dependencies in the model.

Best regards
Søren

Hope it helps

Best regards
Søren

Hello Søren,

it seems I forgot to mention my 4 markers on the thorax. Here is the picture how it looks like:


The PelvisPos XYZ PelvisRot XYZ are all off. I am looking at the PelvisThorax DOF right now.
The lower body is already disabled. Luckily this is the easier part.
Scaling with XYZ is not working. I am getting the following Error:

ERROR(SCR.PRS9) : C:/U..s/b..b/D..s/A..x/A..d/Body/A..n/HumanModel.any(43) : Defined at : C:/U..s/b..b/D..s/A..x/A..d/Body/A..n/B..s/G..l/AnyMan.ClassTemplates.any(181) : 'Height' : Unresolved object

I looked at the Errors and it seems the defined part at AnyMan.ClassTemplates.any(181) was changed in the newer repositories. In the old repository AnyFloat DepthScale was definied as

#var AnyFloat DepthScale = ...SegmentDimensions.Left.FootHeight / 0.0502;
#var AnyFloat WidthScale = ..BodyScale;

In the newer repository it is changed to:

#var AnyFloat DepthScale = ...SegmentDimensions.Right.FootHeight / ....Scaling.StandardParameters.Right.Foot.Height;
#var AnyFloat WidthScale = ...SegmentDimensions.Right.FootWidth / ....Scaling.StandardParameters.Right.Foot.Width;

So that i disabled lower body scaling with XYZ does not work anymore for me.

Right now I am trying the IF condition for left and right handed persons, but i am not sure how the trigger for the if condition should be. Because the markers for RIGHT side and LEFT side are named the same. They only change position. Only the thorax markers remain the same. I am trying right now to define the condition in dependency of my thorax markers. The markers are

Right Hand | CS_2 CS_3 | Left Hand
markers right | CS_1 CS_4 | marker left

and if the marker for example SA_2 on my should is near CS_2 then its right hand else its left hand. But I am not sure how to solve it in AnyBody. Here is my model from Google Drive. I hope it is understandable.

Best regards and thank you for helping
Irzigen

As far as I undertstand I need to follow this steps right?
https://anyscript.org/tutorials/A_Getting_started_modeling/lesson3.html?highlight=pelvisthoraxdriver#step-2-locking-pelvis-thorax-rotation

So this should be in the ExtraDrivers

AnyKinEqSimpleDriver PelvisThoraxDriver =
{
AnyKinMeasure& ref0 = ...HumanModel.BodyModel.Interface.Trunk.PelvisThoraxExtension;
AnyKinMeasure& ref1 = ...HumanModel.BodyModel.Interface.Trunk.PelvisThoraxLateralBending;
AnyKinMeasure& ref2 = ...HumanModel.BodyModel.Interface.Trunk.PelvisThoraxRotation;
DriverPos = pi/180*{0,0,0};
DriverVel = pi/180*{0,0,0};
};
AnyKinEqSimpleDriver SkullThoraxDriver =
{
AnyKinMeasure& ref0 = ...HumanModel.BodyModel.Interface.Trunk.SkullThoraxFlexion;
AnyKinMeasure& ref1 = ...HumanModel.BodyModel.Interface.Trunk.SkullThoraxLateralBending;
AnyKinMeasure& ref2 = ...HumanModel.BodyModel.Interface.Trunk.SkullThoraxRotation;
DriverPos = pi/180*{0,0,0};
DriverVel = pi/180*{0,0,0};
};

With TrialFileName = "C024_20200625_19"; the pelvis starts to rotate with the arm around step ~350. It seems I need more drivers to have my pelvis stops from rotating. I don't know why it happens in this c3d. In other c3d the pelvis moves only a little bit.

Best regards
Irzigen

Just to be sure is my question understandable or should i rephrase it?
I could define with Vicon Nexus the "DominantHand" (right- or lefthanded). Is it possible to read it with an IF-function in AnyBodyTech and switch between my MarkerSets? Or should I create two modells and switch it with an other programm like Python? But second choice is possible but doesn't feel elegant.
I thought something about:

#define DominantHand

#ifdef DominantHand == 1
// define marker right arm
#endif
#ifdef DominanHand == 0
// define markers left arm
#endif

Edit: my pelvis is still rotating like in the reply above, I would appreciate any tipps :slight_smile:
Best Regards

I am very sorry for the slow response somehow this tread was overlooked.

I will try answer your questions one by one.

DominantHand:

Concerning the switch you can do it more or less like you suggest so :

Main ={

#ifndef 
#define DominantHand "R"
#endif

#if DominantHand == "R"
// define marker right arm
#endif
#if DominantHand == "L"
// define markers left arm
#endif
};

In this code dominant hand can optionally be set from somewhere else e.g. if the model is loaded in console application the "DominantHand" can be part of the load and in this way controlled from outside, without changing the model.

Pelvis rotation:
The rotations must be caused by the four marker cluster on thorax.. please try to review the movement of these markers... with the drivers you have the spine will be stiff.

ScalingXYZ:
In the AnyMan.any file please ensure the Height variable is defined, i think the error indicates that could be missing.

Best regards
Søren

Thank you for your reply. Just to be sure: I can define in BodyModelConfig.any in Main following

Main = {
#ifndef DominantHand
  #define DominantHand "Main.ModelSetup.C3DFileData.Groups.PROCESSING.DominantHand.Data"
#endif

// RightHand = 1.0 / LeftHand = 0.0
#if DominantHand == "1.0"
 #define BM_ARM_RIGHT ON
 #define BM_ARM_LEFT OFF
#endif
#if DominantHand == "0.0"
 #define BM_ARM_LEFT ON
 #define BM_ARM_RIGHT OFF
#endif

 #define BM_SCALING _SCALING_LENGTHMASS_
 #define BM_TRUNK_RHYTHM ON
 #define BM_LEG_LEFT OFF
 #define BM_LEG_RIGHT OFF
};

Because if I try it, it sets on default mode and enable both arms. I tried it without quotation marks because I thought it is a float data type like in the description:

#ifndef DominantHand
  #define DominantHand Main.ModelSetup.C3DFileData.Groups.PROCESSING.DominantHand.Data
#endif

// RightHand = 1.0 / LeftHand = 0.0
#if DominantHand == 1.0
 #define BM_ARM_RIGHT ON
 #define BM_ARM_LEFT OFF
#endif
#if DominantHand == 0.0
 #define BM_ARM_LEFT ON
 #define BM_ARM_RIGHT OFF
#endif

but after that I am getting an error: ERROR(SCR.SCN6) : C:/U..s/b..b/D..s/A..x/A..d/A..n/M..s/P..e/S..p/BodyModelConfig.any(19) : 'Main' : Unexpected character.
It seems I call a wrong value type.

Best regards
Irzigen

Hi Irzigen,

The statement

#ifndef DominantHand
  #define DominantHand "Main.ModelSetup.C3DFileData.Groups.PROCESSING.DominantHand.Data"
#endif

will set DominantHand equal to "Main.ModelSetup.C3DFileData.Groups.PROCESSING.DominantHand.Data"

and not either 0 or 1.

It is not possible to read a number in the C3D file structure and set a define with this it would have to be through a define statement passed to a console application.

So in your code it simply never reads the sections switching in and out arms.

Best regards
Søren

Hello Søren,

i could define everything with python and the modell is function.
I have still sometimes the problem with the rotation of pelvis. I know its because i am missing markers on pelvis but I am trying to freeze ThroaxSegment and PelvisSegment after AutoPosition it to my markers. It still not working 100%

I tried define following in the ExtraDrivers:

AnyFolder ExtraDrivers = {
  AnyFolder &JntPos = Main.HumanModel.Mannequin.Posture;
  AnyFolder &JntVel = Main.HumanModel.Mannequin.PostureVel;

  #define BM_MANNEQUIN_DRIVER_DEFAULT ON
  #define BM_MANNEQUIN_DRIVER_GLENOHUMERAL_ABDUCTION_RIGHT OFF
  #define BM_MANNEQUIN_DRIVER_GLENOHUMERAL_FLEXION_RIGHT OFF
  #define BM_MANNEQUIN_DRIVER_GLENOHUMERAL_EXTERNAL_ROTATION_RIGHT OFF
  #define BM_MANNEQUIN_DRIVER_ELBOW_FLEXION_RIGHT OFF
  #define BM_MANNEQUIN_DRIVER_ELBOW_PRONATION_RIGHT OFF
  #define BM_MANNEQUIN_DRIVER_WRIST_FLEXION_RIGHT OFF
  #define BM_MANNEQUIN_DRIVER_WRIST_ABDUCTION_RIGHT OFF
  #define BM_MANNEQUIN_DRIVER_HAND_RIGHT OFF

   AnyKinEqSimpleDriver PelvisThoraxDriver =
   {
     AnyKinMeasure& ref0 = Main.HumanModel.BodyModel.Interface.Trunk.PelvisThoraxLateralBending;
     AnyKinMeasure& ref1 = Main.HumanModel.BodyModel.Interface.Trunk.PelvisThoraxRotation;
     AnyKinMeasure& ref2 = Main.HumanModel.BodyModel.Interface.Trunk.PelvisThoraxExtension;

     DriverPos = pi/180*{
       .JntPos.PelvisThoraxLateralBending,
       .JntPos.PelvisThoraxRotation,
       .JntPos.PelvisThoraxExtension
     };
     DriverVel = pi/180*{
       .JntPos.PelvisThoraxLateralBending,
       .JntPos.PelvisThoraxRotation,
       .JntPos.PelvisThoraxExtension
     };
      Reaction.Type = {Off, Off, Off};
      CType = {Hard, Hard, Hard};
   };

   AnyKinEqSimpleDriver SkullThoraxDriver =
   {
     AnyKinMeasure& ref0 = Main.HumanModel.BodyModel.Interface.Trunk.SkullThoraxFlexion;
     AnyKinMeasure& ref1 = Main.HumanModel.BodyModel.Interface.Trunk.SkullThoraxLateralBending;
     AnyKinMeasure& ref2 = Main.HumanModel.BodyModel.Interface.Trunk.SkullThoraxRotation;

     DriverPos = pi/180*{0,0,0};
     DriverVel = pi/180*{0,0,0};    
     Reaction.Type = {Off, Off, Off};
   };

  //   This is an etsimation of the upper body motion it will enforce that the head is kept above the pelvis medial/laterally
   AnyKinEqSimpleDriver LateralBendDriver ={
     AnyKinLinear lin ={
       AnySeg &ref1=  Main.HumanModel.BodyModel.Trunk.SegmentsLumbar.PelvisSeg;
       AnySeg &ref2=  Main.HumanModel.BodyModel.Trunk.SegmentsThorax.SkullSeg;
     };
     DriverPos={0};
     DriverVel={0};
     MeasureOrganizer={1};
   };

Is there any Driver you would suggest to optimize it?

Thank you in advance
Best regards
irzigen

Hi Irzigen ,

I am not getting the last driver you have this could be in conflict with the pelvis/throrax + thorax/skull driver.

The LateralBendDriver sets the linear measure y direction to zero, but this is the y direction of the global ref system, since the "Ref" property in the AnyKinLinear object has not been set meaning it is "-1" so global y direction in this case.

As i see the markers and the code, you a four markers on the sternum this should be enough to drive thorax since the other two drivers will make the spine stiff, then you do not need the last driver it will only cause trouble,

Sorry if i have missed what the issue is :wink:

Best regards
Søren

Hello Søren,

if i comment out

  //   This is an etsimation of the upper body motion it will enforce that the head is kept above the pelvis medial/laterally
   AnyKinEqSimpleDriver LateralBendDriver ={
     AnyKinLinear lin ={
       AnySeg &ref1=  Main.HumanModel.BodyModel.Trunk.SegmentsLumbar.PelvisSeg;
       AnySeg &ref2=  Main.HumanModel.BodyModel.Trunk.SegmentsThorax.SkullSeg;
     };
     DriverPos={0};
     DriverVel={0};
     MeasureOrganizer={1};
   };

The pelvis will start to tilt like in the picture below, that's why I am using this. Normally the person stands straight on the floor and is not moving its pelvis, only upper limb (arm, shoulders and hands) is moving. I am just trying to constraints the thorax and the pelvis in its position, so only the upper limb is moving after AutoPosition it. I wanted to ask if my solution is good or if there are more optimization I could use for it.


Thank you in advance.

Best regards
Irzigen

Hi Irzigen,

What about driving two rotations between pelvis and global so that the pelvis was always upright wrt to the floor but free to do axial rotations.
Then free up pelvic/thorax flexion + lat bend.

If you decide to keep the AnyKinLinear be careful , the model will behave differently if the subject is pointing in a different direction, because Ref=-1 (Global) in the linear measure.

Best regards
Søren

Hello Søren,

I think I understand what problems could happen.

Would it be possible to provide an example so I can use it in my model? I am happy that is is working right now and am afraid of getting new errors :sweat_smile:
Thank you in advance

Best regards
Irzigen

Hi Irzigen ,

Here is a quick try:


AnyKinEqSimpleDriver LateralBendDriver ={
     AnyKinLinear rot ={
     AnyFixedRefFrame  &ref0=Main.EnvironmentModel.GlobalRef ; //???reference my be incorrect
  AnySeg &ref1=  Main.HumanModel.BodyModel.Trunk.SegmentsLumbar.PelvisSeg;
TypeRotAxedAngles;          
};
     DriverPos={0.0,0};  //may need adjustments...
     DriverVel={0,0};
     MeasureOrganizer={1,2};  // drive y and x rotations leave z open   (default rot sequence is zyx)
   };
Keep the PelvisThoraxDriver 

Best regards
Søren