-1

I would like to be able to simulate the movement of the body on a "carousel" with respect to physics. (centripetal, centrifugal force, angular speed). Below is some sample code.

<!DOCTYPE html>
<html>
    <head>
        <script>
            
            var rotate = Math.PI / 180;
            var ballRotation = 1;
        
            function drawthis() {
    
                var friction = 0.5;

                context.setTransform(1, 0, 0, 1, 0, 0);
                context.clearRect(0, 0, cvs.width, cvs.height);
                context.translate(350, 350);
                context.rotate(rotate);
                context.beginPath();
                context.arc(1, 1, 12, 0, 2 * Math.PI, false);
                context.fill();
                context.beginPath();
                context.arc(0, 0, 150, 0, Math.PI * 2, false);
                context.lineWidth = 6;
                context.stroke();
                
                motion = ballRotation - friction;
                rotate += motion;
                requestAnimationFrame(drawthis);
}
            function init() {
                cvs = document.getElementById("canvas");
                context = cvs.getContext("2d");
                context.clearRect(0, 0, context.width, context.height);
                context.fillStyle = "#ff0000";
                requestAnimationFrame(drawthis);
}
        </script>
    </head>
    <body onload="init()">
            <canvas id="canvas" width="800" height="800"></canvas>
    </body>
</html>

I mean something like this

ttt
  • 300
  • 1
  • 6

1 Answers1

1

Ball on a turn table

Below you will find a simple simulation of a point sliding on a turning wheel. The point represents the contact point of a ball.

The simulation ignores the fact that the ball can roll, or has mass.

The ball slides via a simple friction model, where friction is a scalar value applied to the difference between the balls speed vector, and the speed of the wheel at the point under the ball.

There is only 1 force involved. It is the force tangential to the vector from the ball to the wheel center, subtracted by the ball movement vector and then multiplied by the friction coefficient.

For details on how this is calculated see comments in the function ball.update()

Notes

  • That if the ball starts at the dead center of the wheel nothing will happen.

  • I could not workout if it was the path of the ball you wanted or just the simulation of the ball, so I added both.

  • The ball resets after it leaves the wheel.

  • The wheel is marked with text and center cross so its rotation can be seen.

const ROTATE = Math.PI / 50;
const WHEEL_SIZE = 0.6;
Math.rand = (min, max) => Math.random() * (max - min) + min;
Math.randPow = (min, max, p) => Math.random() ** p * (max - min) + min;

var friction = 0.35;
const ctx = canvas.getContext("2d");
requestAnimationFrame(mainLoop);
ctx.font = "30px arial";
ctx.textAlign = "center";
scrollBy(0, canvas.height / 2 - canvas.height / 2 * WHEEL_SIZE);

function mainLoop() {
    ctx.setTransform(1, 0, 0, 1, 0, 0);
    ctx.clearRect(0, 0, ctx.canvas.width, ctx.canvas.height);
    wheel.update();
    ball.update(wheel, arrow);
    wheel.draw();
    path.draw();
    ball.draw();
    arrow.draw(ball);
    requestAnimationFrame(mainLoop);
}

const path = Object.assign([],{
    draw() {
        ctx.setTransform(1, 0, 0, 1, 0, 0);
        ctx.strokeStyle = "#F00";
        ctx.lineWidth = 1;
        ctx.beginPath();
        for (const p of this) { ctx.lineTo(p.x, p.y) }
        ctx.stroke();
    },
    reset() { this.length = 0 },
    add(point) {
        this.push({x: point.x, y: point.y});
        if (this.length > 1000) {  // prevent long lines from slowing render
            this.shift()
        }
    }
});  
const arrow = {
    dx: 0,dy: 0,
    draw(ball) {
        if (this.dx || this.dy) {
            const dir = Math.atan2(this.dy, this.dx);
            
            // len is converted from frame 1/60th second to seconds
            const len = Math.hypot(this.dy, this.dx) * 60; 
            const aXx = Math.cos(dir);
            const aXy = Math.sin(dir);        
            ctx.setTransform(aXx, aXy, -aXy, aXx, ball.x, ball.y);
            ctx.beginPath();
            ctx.lineTo(0,0);
            ctx.lineTo(len, 0);
            ctx.moveTo(len - 4, -2);
            ctx.lineTo(len, 0);
            ctx.lineTo(len - 4, 2);
            ctx.strokeStyle = "#FFF";
            ctx.lineWidth = 2;     
            ctx.stroke();
        }
    }
};
const ball = {
    x: canvas.width / 2 + 4,
    y: canvas.height / 2,
    dx: 0,  // delta pos Movement vector
    dy: 0,
    update(wheel, arrow) {
        // get distance from center
        const dist = Math.hypot(wheel.x - this.x, wheel.y - this.y);
        
        // zero force arrow
        arrow.dx = 0;
        arrow.dy = 0;
         
        // check if on wheel
        if (dist < wheel.radius) {
            // get tangent vector direction
            const tangent = Math.atan2(this.y - wheel.y, this.x - wheel.x) + Math.PI * 0.5 * Math.sign(wheel.dr);
            // get tangent as vector
            // which is distance times wheel rotation in radians.
            const tx = Math.cos(tangent) * dist * wheel.dr;
            const ty = Math.sin(tangent) * dist * wheel.dr;

            // get difference between ball vector and tangent vector scaling by friction
            const fx = arrow.dx = (tx - this.dx) * friction;
            const fy = arrow.dy = (ty - this.dy) * friction;

            // Add the force vector 
            this.dx += fx;
            this.dy += fy;
        } else if (dist > wheel.radius * 1.7) { // reset ball

            // to ensure ball is off center use random polar coord
            const dir = Math.rand(0, Math.PI * 2);
            const dist = Math.randPow(1, 20, 2);  // add bias to be close to center
            this.x = canvas.width / 2 + Math.cos(dir) * dist;
            this.y = canvas.height / 2 + Math.sin(dir) * dist;
            this.dx = 0;  
            this.dy = 0;        
            path.reset();
        }
        // move the ball
        this.x += this.dx;
        this.y += this.dy;      
        path.add(ball);
    },    
    draw() {
        ctx.fillStyle = "#0004";
        ctx.setTransform(1, 0, 0, 1, this.x + 5, this.y + 5);
        ctx.beginPath();
        ctx.arc(0, 0, 10, 0, 2 * Math.PI);
        ctx.fill();    
        ctx.fillStyle = "#f00";
        ctx.setTransform(1, 0, 0, 1, this.x, this.y);
        ctx.beginPath();
        ctx.arc(0, 0, 12, 0, 2 * Math.PI);
        ctx.fill();    
        ctx.fillStyle = "#FFF8";
        ctx.setTransform(1, 0, 0, 1, this.x - 5, this.y - 5);
        ctx.beginPath();
        ctx.ellipse(0, 0, 2, 3, -Math.PI * 0.75, 0, 2 * Math.PI);
        ctx.fill();  
    },
}
const wheel = {
    x: canvas.width / 2, y: canvas.height / 2, r: 0,
    dr: ROTATE, // delta rotate
    radius: Math.min(canvas.height, canvas.width) / 2 * WHEEL_SIZE,
    text: "wheel",
    update() { this.r += this.dr },
    draw() {
        const aXx = Math.cos(this.r);
        const aXy = Math.sin(this.r);
        ctx.setTransform(aXx, aXy, -aXy, aXx, this.x, this.y);
        ctx.fillStyle = "#CCC";
        ctx.strokeStyle = "#000";
        ctx.lineWidth = 6;
        ctx.beginPath();
        ctx.arc(0, 0, this.radius, 0, 2 * Math.PI);
        ctx.stroke();
        ctx.fill();    
        ctx.strokeStyle = ctx.fillStyle = "#aaa";
        ctx.lineWidth = 2;
        ctx.beginPath();
        ctx.lineTo(-20,0);
        ctx.lineTo(20,0);
        ctx.moveTo(0,-20);
        ctx.lineTo(0,20);
        ctx.stroke();
        ctx.fillText(this.text, 0, this.radius - 16);
    },    
}
<canvas id="canvas" width="300" height="300"></canvas>

Centripetal force

Centripetal is the force towards the center of the turning wheel. However because the ball is sliding the force calculated is not a centripetal force.

You can calculate the centripetal force by scaling the vector from the ball to the center by the dot product of the "vector to center" dot "force vector"

The force vector on the ball is shown as a white arrow. The arrows size is the force as acceleration in pixels per second.

The vector is towards the center but will never point directly at the center of the wheel.

Approximation

This simulation is an approximation. You will need an understanding of calculus and differential equations to get closer to reality.

Using a more complex simulation would only be noticeable if the friction was very close or at 1 and it is easier then to just fix the ball to the wheel, scaling the position from center by an inverse power of the friction coefficient.

Blindman67
  • 51,134
  • 11
  • 73
  • 136
  • That’s very kind of you for trying to clarify the topic, but could you take a look at it again? I have tried to run the simulations many times but my screen is blank all the time. @Blindman67 – ttt Dec 10 '20 at 08:59
  • @ttt I can not see any problems. The demo runs fine on the various devices I have at hand. – Blindman67 Dec 10 '20 at 10:34
  • I couldn't write back earlier. It works, and I start analyzing and thinking about it. Could I use the solution for teaching purposes? I am grateful for your time and at the same time marked the answer as helpful. @Blindman67 – ttt Dec 11 '20 at 10:38
  • @ttt All content on SO is in the public domain and can be used in any way you may wish. It is import to emphasize that the ball in this simulation is sliding not rolling. A rolling ball would behave a little different. – Blindman67 Dec 11 '20 at 11:13