Dancers, no matter the dance form, are susceptible to several different kinds of injuries while dancing or while striking a specific pose. Each year, approximately 80% of dancers in the United Kingdom experience at least one injury that impacts their ability to perform. Dancing injuries, though sometimes temporary, can lead to injuries with lasting effects. My project focuses on modeling a Kathak dancer’s lower body and understanding how joint constraints play a role in a dancer’s movement. By modeling a dancer using both forward and inverse kinematics, my project enables research in simulating realistic motion paths that respect anatomical limitations while still being able to achieve efficient and precise end position goals. This model is crucial not only for understanding how to most efficiently move through positions, but also understanding and lowering injury risk through analyzing range of motion limits and the biomechanical feasibility of transitions between poses.
Introduction
Introduction
Kathak is one of the eight classical dance forms of India, originating from Uttar Pradesh, a state in northern India. The term “Kathak” is derived from the word “Katha,” meaning story, reflecting the dance’s primary focus on storytelling. Kathak incorporates a wide range of footwork, sharp movements, graceful hand gestures, and expressive facial expressions, all of which contribute to the narrative aspect of the dance form. In addition to storytelling, Kathak includes more abstract pieces called Taranas, which are pieces that are fast in tempo, have complex rhythmic patterns, and include fast footwork, a lot of turns, and graceful movements. Kathak dancers often end pieces like Taranas and compositions, which are mini dance pieces within a larger piece, with poses. These poses, typically sharp and focused, are frequently employed at the beginning of performances and reappear periodically, leading to either a transition to another movement or a shift into a new composition. The poses and transitions are the focus of my work, as holding a pose for too long, especially with incorrect foot alignment or angle, can lead to injuries over time, particularly if the incorrect form is repeated frequently. Rapidly switching between positions that involve significant weight shifts can also contribute to injury, as dancers may not have enough time to properly establish correct posture and joint alignment before moving into the next position, which, like holding a position for too long can be harmful in the long run. As a Kathak dancer for the past 11 years, I have personally felt the impact of joint stress and have witnessed how improper technique and rapid transitions can lead to lasting injuries, thus motivating my interest in this topic.
Setting up Transitions Between Dance Poses
Setting up Transitions Between Dance Poses
The first step in modeling the dancer’s lower body was to create points representing the locations of the joints within a 3D dance space. Using parameters from the work of Frederick Wu, I defined five constant variables which held information about the lengths of the various segments of the lower body.
◼
The variable w1 referred to the total length of the dancer’s leg.
◼
The variable w2 referred to the dancer’s waist length, measured from the front of the body.
◼
The variable g1 represented the length of the thigh (including the femur), extending from the hip joint to the knee.
◼
The variable g2 referred to the length from the knee to the ankle, including the tibia and fibula.
◼
The variable g3 held the value for the length of the dancer’s foot.
Leg segment constant initialization:
In[]:=
{w1,w2,g1,g2,g3}={75,10,30,35,10};
Forward kinematics is the process of calculating the position of a robot (in my project, a dancer) based on joint angles and length parameters. In line with the conventions of forward kinematics, I used Denavit-Hartenberg (D-H) notation to assign coordinate frames to the links (connections between joints), which made it easier to model the dancer’s structure and derive the equations and relationships required to calculate movement. The D-H convention used four parameters: αᵢ₋₁, aᵢ₋₁, dᵢ, and θᵢ, which represent link twist, link length, link offset, and joint angle, respectively.
In the following code, for each leg (left and right, respectively) 7 coordinates are used, the first three coordinates refer to the hip joint and the waist (with a length of w2) on each side. The fourth coordinate refers to the knee joint, with the femur having a length of g1. The next three coordinates refer to the ankle joint, including the tibia, with a length of g2.
Coordinates of each of the joints of the lower body, split into the waist, the right leg, and the left leg:
In[]:=
lowerBody={{0,0,w1,θW2+Pi/2}};
In[]:=
legRight={{0,w2,0,θLR1},{Pi/2,0,0,θLR2-Pi/2},{Pi/2,0,0,θLR3},{0,g1,0,θLR4},{0,g2,0,θLR5},{-Pi/2,0,0,θLR6},{0,0,0,θLR7}};
In[]:=
legLeft={{0,-w2,0,θLL1},{Pi/2,0,0,θLL2-Pi/2},{Pi/2,0,0,θLL3},{0,g1,0,θLL4},{0,g2,0,θLL5},{-Pi/2,0,0,θLL6},{0,0,0,θLL7}};
Using the predefined joint coordinates and segment lengths, I constructed the lower body by first joining the waist (lowerBody) with the right leg (legRight) to form lowerBodyLegRight. Then, I joined this structure with the left leg (legLeft) to create lowerBodyLegLeft, completing the basic 3D model of the dancer’s legs and waist.
Combining the segments to form the whole lower body:
In[]:=
lowerBodyLegRight=Join[lowerBody,legRight];lowerBodyLegLeft=Join[lowerBody,legLeft];
With the model of the dancer’s legs in place, I used Wu’s joint transformation matrix to compute the position and orientation of each joint relative to the previous joint. The function jointTransformationMatrix takes a Denavit-Hartenberg (D-H) parameter table DH and an index i and extracts the four parameters, link twist (α), link length (a), link offset (d), and joint angle (θ), to construct a homogeneous transformation matrix. This matrix applies a series of trigonometric transformations to represent both rotation and translation from one joint to the next, enabling the modeling of movement through forward kinematics.
Forming a homogenous transformation matrix given D-H parameter table and an index:
In[]:=
jointTransformationMatrix[DH_,i_]:=Block[{α,a,d,θ},{α,a,d,θ}=DH〚i〛;{{Cos[θ],-Sin[θ],0,a},{Sin[θ]Cos[α],Cos[θ]Cos[α],-Sin[α],-Sin[α]d},{Sin[θ]Sin[α],Cos[θ]Sin[α],Cos[α],Cos[α]d},{0,0,0,1}}];
In order to enable the movement and manipulation of the right leg, I used Wu’s transformation functions to compute a series of link transformations for each individual joint. Using the jointTransformationMatrix function, a transformation matrix for each pair was generated for adjacent joints within the lowerBodyLegRight. To capture the cumulative effect of these transformations along the leg, I computed the product of the individual link transformations, ensuring that each transformation was applied in sequence, such that each joint’s position and orientation is properly calculated relative to all previous joints. This setup allows the leg to move as a coherent unit while maintaining the correct relative positions and orientations of the joints.
I applied the transformations above to actual points in 3D space through the use of the TR4[no, vec]. TR4[no, vec] applies the cumulative transformation up to joint “no” to the vector “vec”, converting it into global coordinates, and enabling the movement and manipulation of the lower body’s right leg as a coherent unit, rather than broken up segments:
In[]:=
Table[linkTransformation4[i-1,i]=jointTransformationMatrix[lowerBodyLegRight,i],{i,Length@lowerBodyLegRight}];linkTransformation4[0,i_]:=linkTransformation4[0,i]=Fold[Dot,linkTransformation4[0,1],Table[linkTransformation4[j,j+1],{j,i-1}]];Do[linkTransformation4[0,i],{i,Length@lowerBodyLegRight}];TR4[no_,vec_]:=TR4[no,vec]=Flatten[Dot[linkTransformation4[0,no],Transpose[List[Append[vec,1]]]]]〚1;;3〛;
The same logic was applied to the left leg. By using Wu’s code to split up the link transformation to the lower body right leg and the lower body left leg, I was able to ensure that a transformation in one leg does not necessarily require the other leg to move the same amount and in the same exact way, allowing for the motion to be split up depending on the leg.
In[]:=
Table[linkTransformation5[i-1,i]=jointTransformationMatrix[lowerBodyLegLeft,i],{i,Length@lowerBodyLegLeft}];linkTransformation5[0,i_]:=linkTransformation5[0,i]=Fold[Dot,linkTransformation5[0,1],Table[linkTransformation5[j,j+1],{j,i-1}]];Do[linkTransformation5[0,i],{i,Length@lowerBodyLegLeft}];TR5[no_,vec_]:=TR5[no,vec]=Flatten[Dot[linkTransformation5[0,no],Transpose[List[Append[vec,1]]]]]〚1;;3〛;
With the ability to make these transformations on each of the legs, I used Wu’s frameModel to create graphical representations of the leg joints and segments to visualize the model. These visualizations are color-coded with arrows and points to represent coordinates at the joints and allow for easier interpretation of the orientation of the model. Each axis is represented by a different color: purple represents the x-axis, green, the y-axis, and yellow, the z-axis. Red marks the origin point of the frame.
Creating a color-coded graphical representations of the leg joints and the segments:
In[]:=
frameModel[TR_,n_]:=Module[{l=10},If[n0,{Black,Text[Style[#〚1〛,Italic,16],#〚2〛]&/@Transpose[{DisplayForm[SubscriptBox[#,n]]&/@{"x","y","z"},{{.9l,0,0},{0,.9l,0},{0,0,.9l}}}],Red,PointSize[.02],Point[{0,0,0}],Arrowheads[.01],Purple,Arrow[{{0,0,0},{.8l,0,0}}],Green,Arrow[{{0,0,0},{0,.8l,0}}],Yellow,Arrow[{{0,0,0},{0,0,.8l}}]},{Black,Text[Style[#〚1〛,Italic,16],#〚2〛]&/@Transpose[{DisplayForm[SubscriptBox[#,n]]&/@{"x","y","z"},{TR[n,{.9l,0,0}],TR[n,{0,.9l,0}],TR[n,{0,0,.9l}]}}],Red,PointSize[.02],Point[TR[n,{0,0,0}]],Arrowheads[.01],Purple,Arrow[{TR[n,{0,0,0}],TR[n,{.8l,0,0}]}],Green,Arrow[{TR[n,{0,0,0}],TR[n,{0,.8l,0}]}],Yellow,Arrow[{TR[n,{0,0,0}],TR[n,{0,0,.8l}]}]}]];
Using Wu’s floorModel, to complete the visuals and provide helpful spatial context for the dancer model, I created a dance floor composed of tiled squares. The floor mimics a checkerboard or chessboard pattern by varying the opacity of the tiles, helping to visualize the dancer in the 3D environment.
Forming a simple checkered floor as the dance floor for my model:
In[]:=
floorModel[{{i_,j_},{x_,y_,z_},d_}]:={Opacity[If[OddQ[i],0,.5]+If[OddQ[j],0,.5]],Black,Polygon[{{x-d/2,y-d/2,z},{x+d/2,y-d/2,z},{x+d/2,y+d/2,z},{x-d/2,y+d/2,z}}]};prts=Flatten[With[{d=40},Table[{{Floor[i/d],Floor[j/d]},{i,j,0},d},{i,-100,100,d},{j,-100,100,d}]],1];
With the foundational model complete and visually formatted, I defined joint constraints to reflect the physical limits of a dancer’s leg movements. Each joint in the model was bounded with a specific range of motion to ensure realistic and anatomically accurate behavior. These bounds were chosen based on the functional range of motion required for a Kathak dancer to perform traditional movements effectively. These constraints helped preserve the integrity of the dancer’s form and ensure that any simulated motion remained within the biomechanical limits for a typical Kathak dancer.
The variable, bounds, is a list composed of lists which represents the angular limits for each joint, with each specified pair of values representing bounds in radians. Each pair {min, max} defined the allowable range of rotation for a joint, thus preventing the model from shifting through unrealistic or physically impossible positions. The variable bounds is formatted starting with the bounds of the dancer’s right leg, moving from waist, to hip1, hip2, hip3, knee1, ankle1, and ankle 2. The next 7 values represents the bounds of the joints on the left leg.
In[]:=
bounds={{-Pi/4,Pi/4},{-Pi/2,Pi/2},{-Pi/4,Pi/8},{-Pi,Pi/4},{0,Pi},{-Pi/8,Pi/8},{-Pi/8,Pi/8},{-Pi/4,Pi/4},{-Pi/2,Pi/2},{-Pi/8,Pi/4},{-Pi,Pi/4},{0,Pi},{-Pi/8,Pi/8},{-Pi/8,Pi/8}};
To store and access the joint angles associated with a specific Kathak position, I developed a function named pattern that accepts two parameters: the name of the position as a string (p) and the joint index (int). It returns the corresponding angle value for the specified position and joint. Each list within the function represented a full lower body pose by specifying angular values for all 14 of the joints.
In[]:=
pattern[p_,int_]:=Which[p=="natawari1",{-Pi/16,9Pi/32,0,-9Pi/64,Pi/4,-3Pi/32,0,-Pi/16,Pi/8,3Pi/32,3Pi/32,0,Pi/8,0}[[int]],p=="Vposition",{-Pi/16,5Pi/32,0,Pi/32,0,-Pi/32,-Pi/32,-Pi/16,0,0,0,0,0,0}[[int]],p=="Sitting",{0,9Pi/32,Pi/32,-9Pi/32,27Pi/32,-Pi/8,0,0,-9Pi/32,-Pi/32,-11Pi/16,27Pi/32,0Pi/8,0}[[int]],p=="neutral",{0,0,0,0,0,0,0,0,0,0,0,0,0,0}[[int]],p=="BackStrongToe",{0,7Pi/32,0,-Pi/16,Pi/8,0,0,0,-11Pi/32,0,Pi/32,5Pi/32,0,0}[[int]],p=="Kaliya",{5Pi/32,-Pi/16,Pi/4,-7Pi/16,11Pi/32,Pi/8,0,5Pi/32,-Pi/8,-Pi/32,-3Pi/16,Pi/4,-Pi/32,-Pi/32}[[int]]];
After defining joint bounds based on human anatomical constraints and the flexibility required for a Kathak dancer, I developed a function to smoothly transition between a list of predefined dance positions. I used Interpolation to compute intermediate joint angle values across time, allowing the dancer’s leg movements to appear continuous and natural rather than abrupt. Interpolation gave me all of the intermediate values within a range for a starting and ending position.
Creating a list that holds all of the values of the interpolation for a specific joint between 6 positions in a specific order:
In[]:=
interpolationOfTransitionsOrder1=Table[Interpolation[Map[pattern[#,i]&,{"Kaliya","Sitting","neutral","natawari1","BackStrongToe","Vposition"}]],{i,1,14}];
Here is what the first 3 indices look like:
In[]:=
interpolationOfTransitionsOrder1[[1;;3]]
Out[]=
InterpolatingFunction,InterpolatingFunction,InterpolatingFunction
For visualization purposes later in the essay, I created a similar list as the one directly above, but this time changed the arrangement of the positions in the list:
In[]:=
interpolationOfTransitionsOrder2=Table[Interpolation[Map[pattern[#,i]&,{"Kaliya","natawari1","Sitting","BackStrongToe","Vposition","neutral"}]],{i,1,14}];
With the interpolation functions for each joint in place, this data can now be used to generate smooth transitions between dance positions.
I created a function that constructs a list of joint angle configurations, each representing a frame in time, sampled at 0.25-second intervals across a total duration of 5 seconds (resulting in 21 time steps from t = 1 to t = 6):
In[]:=
order1OfTransitionsPattern[t_]:=Transpose[Table[interpolationOfTransitionsOrder1[[i]][#]&[Range[1,6,0.25]],{i,1,14}]][[t]]
While modeling transitions in my simulator, I encountered a challenge: some interpolated joint angles exceeded human anatomical limits. One example of this was with the knee joint, where it bent forward beyond natural range during transitions from the neutral (straight-leg) position. Therefore, to ensure that all joint transitions remained within realistic movement bounds, I used the previously defined bounds to constrain the interpolated angles. For each joint at each time step, I checked whether the interpolated value exceeded its valid range. If the transitional angle of a specific joint was lower than the value of the bounded joint, I would then clamp that transitional angle to the lowest bound of the joint. On the other hand, if the transitional angle was greater than the value of the bounded joint, I clamped that transitional angle value to the highest bound of the joint. Finally, if the value was in-between the lowest bound and the highest bound, the original transitional joint value was maintained. This change resulted not only in smoother transitions, but more anatomically plausible transitions between joint poses, preventing unnatural or physically impossible movements such as hyperextension of the knee.
Clamping each of the interpolated joint angle values at each 0.25 second intervals, where if the angle is lower than the min bound, clamping it to the min bound and if the angle is great than the max bound, clamping it to the max bound:
In[]:=
clampedAnglesOrder1OfTransitions=Table[Which[(order1OfTransitionsPattern[i][[j]]<bounds[[j]][[1]]),bounds[[j]][[1]],(order1OfTransitionsPattern[i][[j]]>bounds[[j]][[2]]),bounds[[j]][[2]],True,order1OfTransitionsPattern[i][[j]]],{i,1,21},{j,1,14}];
Here is what the first 3 elements of clampedAnglesOrder1OfTransitions looks like:
In[]:=
clampedAnglesOrder1OfTransitions[[1;;3]]
Out[]=
0.490874,-0.19635,,-1.37445,1.07992,0.392699,0.,0.490874,-0.392699,-0.0981748,-0.589049,0.785398,-0.0981748,-0.0981748,0.284553,0.461728,,-1.3825,2.28717,-0.0161068,0.,0.284553,-0.746282,-0.10201,-1.63752,2.06704,-0.0375825,-0.0590583,{0.141126,0.822214,0.337476,-1.28548,2.87161,-0.263845,0.,0.141126,-0.926524,-0.104311,-2.19052,2.73049,-0.00613592,-0.0306796}
π
8
π
8
To visualize the interpolation of each of the joints using the original interpolationOfTransitions, I used Plot to display the evolution of each joint angle over time. The graph below shows two different sequences of poses and illustrates how the angles of 14 joints change over time as the dancer transitions through six dance positions. As shown in the two graphs, certain pose sequences result in inefficient joint angle trajectories, where some angles oscillate rapidly between positive and negative values, indicating excessive and unnecessary movement. This highlighted the need for optimization. My next step was to model the transitions between dance poses and, from that, determine the most efficient arrangement of poses to minimize extraneous joint movement while preserving the integrity of the choreography, by ensuring that no poses were removed but potentially reordered for smoother transitions.
Doing the same thing as the previous two lines of code, but for interpolationOfTransitionsOrder2:
Plotting the interpolated values for each of the joints in the two different arrangements of the positions:
Modeling the Transitions Between Dance Poses
Modeling the Transitions Between Dance Poses
To model and visualize the transitions between dance poses, I started with Wu’s code, but then developed my own function posImg[num_], which generates a 3D graphical representation of the dancer at a specific timestamp num. Each frame depicted the dancer’s position at a given moment during the transition sequence.
Creating a function that prints out the 3D graphics of the dancer for the first arrangement of positions:
Finally, I modeled the full step-by-step transition between the six Kathak dance positions by generating a sequence of poses using the posImg function. Each frame corresponded to one of the 21 time steps (sampled at 0.25-second intervals), capturing the gradual motion as the dancer moves from one position to the next.
Calling the previous function and animating it such that it smoothly animates through all of the joint angle positions:
Finding the Most Efficient Arrangement of Poses
Finding the Most Efficient Arrangement of Poses
As covered earlier, when plotting the interpolated angles for a specific sequence of positions, I observed inefficiencies in the transitions. This motivated the next step of finding the most efficient arrangement of poses from a given set. To implement this, I first needed to generalize the earlier structures, interpolationOfTransitions, correctedAngles, and pattern2, into versions that could handle arbitrary permutations of the dance poses. Thus, I introduced three new functions, interpolationOfPermutations, moreCorrectedAngles, and pattern3.
Creating three functions that help find the most efficient arrangement of positions, given a specific index.
interpolationOfPermutations: This function generated interpolations of joint angles for any permutation of the pose sequence, where it replaced the fixed sequence used in interpolationOfTransitions, allowing a comparison of different pose orders in terms of movement efficiency:
permutationPattern: This function mirrors the structure of clampedAnglesOrder1OfTransitions, but instead of using the fixed sequence in interpolationOfTransitions, it accessed interpolated values from interpolationOfPermutations, making it compatible with dynamic pose orderings:
clampedAnglesPermutation: Similar to clampedAnglesOrder1OfTransitions, this function clamps joint angles to fall within the physically possible range defined by bounds. However, it operates on the interpolated angles from interpolationOfPermutations, ensuring that joint constraints are respected across all permutations being tested:
Using these functions, I iterated through each of the permutations of the order of positions to see which sequence had the smallest error between each of the pairs of joint values between two positions. I then added these errors to one another, which allowed me to determine which arrangement produced the smoothest transitions, as reflected by the lowest total mean error. Since this piece of code takes hours to run, I pre-ran it and determined that the smallest error was calculated at the 17th permutation of the permutations of “Kaliya”, “Sitting”, “natawari1”, “Vposition” which was the order natawari1, V position, Kaliya, and then Sitting. This order makes sense as the Natawari1 position has the joints extended out to the right, and as we go through the rest of the list, the joint angles slowly shift towards the left.
Code that returns a list of each of the errors in each permutation between the joints in each of the n-1 positions (where n represents the number of positions): - Note: This takes a very long time to run.
As the above code takes around 2-3 hours to run, I saved each of the errors in the variable angleDifferences for easy access during the rest of the computation:
Finding the smallest error in the list of all angleDifferences (errors):
This function is the same as the earlier model of the dancer, except I swapped out clampedAnglesOrder1OfTransitions for clampedAnglesPermutation, allowing for the model to have angles passed in and to model as a parameter, and the most efficient arrangement of dance poses be displayed. Function for modeling the dancer moving through the most efficient arrangement of poses, where the variable clampedAnglesOrder1OfTransitions from earlier was swapped out for clampedAnglesPermutation:
Calling the previous function and animating it such that it smoothly animates through all of the joint angle positions for the most efficient arrangement of poses:
Movement to a Position Using Inverse Kinematics
Movement to a Position Using Inverse Kinematics
With a method already in place to model joint movement using pre-defined angular relationships, I extended the approach by implementing inverse kinematics. This allowed for greater generalization, where rather than specifying joint angles directly, I can now determine the angles required for the leg to move from a starting pose to a desired end position in 3D space, by providing the model the lengths of the limb segments and the target position of the joints. To accomplish this, I implemented a specific type of inverse kinematics known as Forward And Backward Reaching Inverse Kinematics (FABRIK). FABRIK works by iteratively adjusting the joint positions in two phases. The first phase is forward reaching, where the chain of segments moves from the end effector/final position (ankle) towards the root/starting position (hip) to reach the target. The second phase is backward reaching, where the root is restored to its initial position, and the rest of the chain is adjusted towards the final position. This process is continuously repeated until the error: the distance between the final joint and the target, is within a small acceptable range.
Within the function, in order to ensure that the movement between 2 time frames is not too large, a maxDelta variable was used, making sure that each step of the function only moves a specific amount of the joint angle.
Creating a function that given the position of each of the segments, the lengths of the segments, the target position, angle constraints, and how much each time the function is run the angle should move, returns the final joint position after reaching the point and within a specific error amount:
To account for the restraints of joints, I developed a function called helper, which accepts 2 vectors (the vectors coming out of a specific joint and going in the direction of the two adjacent joints from that joint), and the bounds of that angle. Given that, if the amount we want to move in the fabrikStep function is smaller than or greater than the bounds of the joint, then a clamp is applied to restrict the movement to be within the bounds of the joint. A helper function that given two vectors, clamping the vector into the bounds of the that joint:
For the inverse kinematics functions, I began by solving the simple problem of moving a robotic limb to a specific target point, given fixed segment lengths and predefined initial joint positions. This approach allowed me to understand how inverse kinematics could work with a very simple example of robotic arm segments before expanding the idea to the broader theme of modeling dance movements.
Tester method for a simple example of modeling inverse kinematics of using 3 segments and 4 joints to go t a target location.
Here is what the first and last 3 elements of ikSet look like:
Here is what the animation of the inverse kinematics function running on 3 segments to each a specific point looks like:
Using the basic robotic arm simulator, I wanted to create a more realistic representation of a dancer, by modeling a knee bend in which the foot remains fixed to the ground while the hip (or upper leg) moves down towards the feet. This was different from my earlier model of dance transitions, where bending the knees caused the foot to lift off from the ground while the hips stayed stationary. By allowing the hips to move downward while anchoring the foot, the new model was able to more accurately reflect how a dancer’s body would behave during a simple movement like bending the knees which is seen in a variety of dance poses and movements.
Modeling the bending of 1 single leg:
Building upon the single-leg model, I duplicated the code to allow both legs to coexist within the same graphic, and allow both the legs to bend simultaneously at the same rate to reach the same position, simulating the natural movement of bending both knees at the same time as seen in real life.
Model of bending two legs at the same rate and reaching the same location 4 units apart from one another:
To make the two-leg bending model more specific to Kathak, I began by developing a simple lunge. In this pose, the dancer’s hips stayed stationary while the legs extended outward into the lunge position, maintaining a proper bent-knee stance while completing the lunge.
Creating a model of a simple lunge:
Finally, to capture the more nuanced and complex nature of Kathak, where a dancer stabilizes the hips while moving the feet, and then stabilizes the feet while moving the hips, I improved the lunge model. I separated the movement into two different phases. The first phase involved the feet extending outward, and the second one involved the knees bending as the hips moved down. This separation of movements allowed me to more accurately model the transitions of Kathak, while also addressing a limitation in the previous model, where bending the knees caused the feet to lift rather than the hips to move downward.
Model of a lunge with changing stable points:
Conclusion and Future Works
Conclusion and Future Works
Overall, even with only modeling 6 positions through forward kinematics and developing an inverse kinematics function capable of simulating a lunge, this project lays the foundation for more comprehensive understanding of dance and joint constraints’ relations to injuries and performance optimization. In the future, I want to expand the number of positions modeled in my project. To better understand transitions, I want to shift from simple positions to singular dance moves and model all the transitions between those. Additionally, it would be interesting to model transitions using inverse kinematics to find the best way to achieve a specific target position given starting positions. Finally, along with analyzing joint restraints on each of the joints in the legs, I would like to expand to being able to analyze joint stress, not only within the legs, but for the whole body, as the movement in the upper body can also have an effect on the injuries and stresses impacting the lower body.
Citations
Citations
◼
Frederick Wu (2015), “Kinematics of Biped Legs for Humanoid Robots” Wolfram Demonstrations Project. demonstrations.wolfram.com/KinematicsOfBipedLegsForHumanoidRobots/
◼
Dobson, Roger. “Eight in 10 Dancers Have an Injury Each Year, Survey Shows.” BMJ : British Medical Journal, vol. 331, no. 7517, Sep. 2005, p. 594. PubMed Central, https://doi.org/10.1136/bmj.331.7517.594-b.
Acknowledgements
Acknowledgements
I would like to acknowledge my mentor, Jenny Wang, for her endless support throughout the project, whether it be coming up with possible directions for extensions or helping debug code. I’d also like to thank Aayush Dubey and Damla Temur for their help in aiding in my understanding of the initial source code and working through the Denavit-Hartenberg Convention with me respectively. I would also like to thank William Choi-Kim for his help with the concept of inverse kinematics and providing tons of support when implementing my own inverse kinematics function. I would additionally like to thank Anne Shuai, Anoushka Muchhal, and other TAs for making project time so much more fun by being open to talking about my project during breaks and helping with the small issues I faced throughout the process. I would also like to thank my dance teacher, Charlotte Moraga, whose guidance and dedication have taught me everything I know about Kathak. I would like to thank Eryn Gillam and Megan Davis for always being open to chat about my project and provide me with possible directions I could take my project in. Finally, I would like to thank Rory Foulger and Dr. Stephen Wolfram for aiding in the ideation process and for the opportunity to work on this project and receive all the help and support I did.
CITE THIS NOTEBOOK
CITE THIS NOTEBOOK
Modeling Kathak dancers' lower bodies through forward and inverse kinematics
by Aanya Gupta
Wolfram Community, STAFF PICKS, July 10, 2025
https://community.wolfram.com/groups/-/m/t/3498889
by Aanya Gupta
Wolfram Community, STAFF PICKS, July 10, 2025
https://community.wolfram.com/groups/-/m/t/3498889