Message Boards Message Boards

[WSS22] 2D simulator for differential robots in The Wolfram Language

Posted 2 years ago

POSTED BY: Carlos Vidal
2 Replies

I think it's important to discuss how adding a scoring system makes the simulation more game-like and how moving obstacles increase the challenge, it would be like doing a knowledge transfer in a dynamic environment like Viva. And sort of compress it down to just kind of a human, something that fits in the finite minds that we have. We have to close our eyes and ignore lots of details and say we care about the big picture of what's happening. The way that that equivalency works, whether one could kind of imagine different sorts of levels that gets to the kind of equivalencing that we're doing.

DynamicModule[{robotPos = {50, 25}, 
  targetPos = RandomInteger[{1, 99}, 2], 
  obstacles = 
   Table[{RandomInteger[{10, 90}, 2], RandomReal[{-2, 2}, 2]}, {5}], 
  score = 0, gameOver = False}, 
 Dynamic@EventHandler[
   Refresh[If[! gameOver, 
     obstacles = Map[Function[obstacle, {pos, vel} = obstacle;
        newVel = vel;
        If[pos[[1]] + vel[[1]] < 0 || pos[[1]] + vel[[1]] > 100, 
         newVel[[1]] = -vel[[1]]];
        If[pos[[2]] + vel[[2]] < 0 || pos[[2]] + vel[[2]] > 50, 
         newVel[[2]] = -vel[[2]]];
        {pos + newVel, newVel}], obstacles];
     If[Norm[robotPos - targetPos] < 3, score++;
      targetPos = While[True, newT = RandomInteger[{5, 95}, 2];
        If[
         And @@ (Norm[newT - #[[1]]] > 5 & /@ obstacles) && 
          Norm[newT - robotPos] > 5, Break[newT]]]];
     If[AnyTrue[obstacles, Norm[robotPos - #[[1]]] < 3 &], 
      gameOver = True]];
    Graphics[{{FaceForm[LightGray], EdgeForm[Blue], 
       Rectangle[{0, 0}, {100, 50}]}, {FaceForm[Green], 
       PointSize[0.06], Point[targetPos]}, {FaceForm[Red], 
       PointSize[0.04], 
       Point[#[[1]] & /@ obstacles]}, {FaceForm[Cyan], EdgeForm[Blue],
        Disk[robotPos, 2]}, 
      Text[Style["Score: " <> ToString[score], Bold, 16], {5, 46}], 
      If[gameOver, {Text[
         Style["GAME OVER", Red, Bold, 36], {50, 25}, {0, 0}], 
        Text[Style["Final Score: " <> ToString[score], Black, Bold, 
          16], {50, 15}, {0, 0}]}]}, PlotRange -> {{0, 100}, {0, 50}},
      ImageSize -> 600], 
    UpdateInterval -> 0.05], {"UpArrowKeyDown" :> 
     If[! gameOver && robotPos[[2]] < 48, robotPos[[2]] += 2], 
    "DownArrowKeyDown" :> 
     If[! gameOver && robotPos[[2]] > 2, robotPos[[2]] -= 2], 
    "LeftArrowKeyDown" :> 
     If[! gameOver && robotPos[[1]] > 2, robotPos[[1]] -= 2], 
    "RightArrowKeyDown" :> 
     If[! gameOver && robotPos[[1]] < 98, robotPos[[1]] += 2]}]]

Game Over

Building on @Carlos Vidal's foundational work in simulating differential robots, it's a more complicated story than we're just playing a video game and somebody's in it. There's sort of a question of something like take the concept of life. Life on Earth has certain characteristics. It has a great deal of orchestration of molecular processes and I don't know how really to characterize that. Life at the level of individual molecules, it's orchestrating how this moves around. Organic chemistry, for all it matters they're bouncing around randomly. In life it seems to be the case that molecules are being transported, proteins are moving with very specific ways to each other relative to molecules. It looks like a computation. It really helps to have self-reproduction because once you manage to get that thing that works that operates like life then you can get to make lots of copies of it you've sort of replicated that achievement. This question of how that builds up is not clear, and that relates to questions about the origins of life and so on. We are not the first instance of life; if life is defined in sort of this molecular scale orchestration it could happen that there's a life 1.0 and it provided the foundation for life 2.0 3.0, who knows where we are in the sequence of forms of life so to speak. Now, it's sort of analogous to what happens in computer systems.

DynamicModule[{robotX = 50, robotY = 25, score = 0, targets, 
  vel = 1.2, size = 2}, 
 targets = 
  Table[{RandomInteger[{10, 90}], RandomInteger[{10, 40}], 
    RandomReal[{-vel, vel}], RandomReal[{-vel, vel}]}, {5}];
 Dynamic@
  Refresh[targets = 
    Table[If[Norm[{robotX, robotY} - {t[[1]], t[[2]]}] < size*2, 
      score++;
      {RandomInteger[{10, 90}], RandomInteger[{10, 40}], 
       RandomReal[{-vel, vel}], RandomReal[{-vel, vel}]}, 
      Module[{x = t[[1]] + t[[3]], y = t[[2]] + t[[4]], vx = t[[3]], 
        vy = t[[4]]}, 
       If[x < 0 || x > 100, vx = -vx; x = Clip[x, {0, 100}]];
       If[y < 0 || y > 50, vy = -vy; y = Clip[y, {0, 50}]];
       {x, y, vx, vy}]], {t, targets}];
   EventHandler[
    Graphics[{{FaceForm[LightGray], EdgeForm[Blue], 
       Rectangle[{0, 0}, {100, 50}]}, {FaceForm[Cyan], 
       EdgeForm[Darker@Cyan], 
       Disk[{robotX, robotY}, size]}, {FaceForm[Red], 
       EdgeForm[Darker@Red], Disk[#[[;; 2]], size] & /@ targets}, 
      Text[Style["Score: " <> ToString[score], Bold, 24, White], {50, 
        45}, Background -> Darker@Gray]}, 
     PlotRange -> {{0, 100}, {0, 50}}, ImageSize -> 600, 
     Background -> Lighter[Gray, 0.7]], {"UpArrowKeyDown" :> 
      If[robotY < 50 - size, robotY += 2], 
     "DownArrowKeyDown" :> If[robotY > 0 + size, robotY -= 2], 
     "LeftArrowKeyDown" :> If[robotX > 0 + size, robotX -= 2], 
     "RightArrowKeyDown" :> If[robotX < 100 - size, robotX += 2]}, 
    PassEventsDown -> True], UpdateInterval -> 0.03, 
   TrackedSymbols :> {}]]

Obstacles

Instead of the original moving obstacles with the scoring system based on the lose condition of encountering an obstacle, we can transform the simulator into a game-like environment including the win condition of obstacles moving in an evolving scenario. We can expand the original obstacle pickup mechanic to include obstacles with velocity-based movement. Obstacles now bounce off arena boundaries, simulating real-world physics. Rather than creating a challenging environment where robots must navigate unpredictable moving objects, we can alter the raw machine code of a computer system.

drawState[arena_, robot_, targets_, score_, time_] := 
  Graphics[{FaceForm[LightGray], EdgeForm[Blue], 
    arena, {FaceForm[Cyan], PointSize[0.06], 
     Point[robot]}, {FaceForm[Red], PointSize[0.04], 
     Point[#] & /@ targets}, 
    Text[Style["Score: " <> ToString@score, Bold, 18], {5, 47}], 
    Text[Style["Time: " <> ToString@time, Bold, 18], {85, 47}]}, 
   ImageSize -> 600, PlotRange -> {{-2, 102}, {-2, 52}}];
DynamicModule[{pos = {50, 25}, targets = {}, score = 0, timeLeft = 30,
   gameActive = False, startTime, lastUpdate}, 
 Column[{Button[
    Dynamic[If[gameActive, "Playing...", "Start New Game"]], 
    If[! gameActive, pos = {50, 25};
     targets = Table[{RandomInteger[100], RandomInteger[50]}, 3];
     score = 0;
     timeLeft = 30;
     gameActive = True;
     startTime = AbsoluteTime[];
     lastUpdate = startTime;], Enabled -> Dynamic[! gameActive]], 
   Dynamic[If[gameActive, 
     With[{currentTime = AbsoluteTime[]}, 
       timeLeft = 30 - (currentTime - startTime);
       If[timeLeft <= 0, gameActive = False];
       If[currentTime - lastUpdate > 0.1, 
        targets = 
         Map[# + {RandomReal[{-0.5, 0.5}], RandomReal[{-0.5, 0.5}]} &,
           targets];
        lastUpdate = currentTime;];];];
    With[{newScore = 
       score + Length@Cases[targets, t_ /; Norm[t - pos] < 3]}, 
     If[newScore > score, 
       targets = 
        Join[Table[{RandomInteger[100], RandomInteger[50]}, 
          newScore - score], 
         DeleteCases[targets, t_ /; Norm[t - pos] < 3]];
       score = newScore;];];
    EventHandler[
     drawState[Rectangle[{0, 0}, {100, 50}], pos, targets, score, 
      Floor@timeLeft], {"UpArrowKeyDown" :> 
       If[gameActive && pos[[2]] < 50, pos += {0, 1}], 
      "DownArrowKeyDown" :> 
       If[gameActive && pos[[2]] > 0, pos -= {0, 1}], 
      "LeftArrowKeyDown" :> 
       If[gameActive && pos[[1]] > 0, pos -= {1, 0}], 
      "RightArrowKeyDown" :> 
       If[gameActive && pos[[1]] < 100, pos += {1, 0}]}, 
     Enabled -> Dynamic[gameActive]]], 
   Dynamic[If[! gameActive && timeLeft <= 0, 
     Style["Game Over! Final Score: " <> ToString@score, Red, 18], 
     ""]]}]]

Target Movement

Now if I remember the Matrix movie, there were some miracles that happened. There were some things that deviated from the mere computational rules that were supposed to run the universe. Well, the evidence is often quoted in some religions for the existence of God; there can be miracles that deviate from the laws of physics which are the discretionary acts of God independent from the laws of nature as they are set in definite form. In our model of Physics, there's sort of more information here. There really is a definable rule. One's really starting from this Ruliad object. The Ruliad is the set of all possible computations..all possible rules that the Universe can start out. We all agree on the laws of Physics more or less because we're really close in Rulial space. We can imagine some alien that's really far far away but just as we're living all on one planet and if we all agree on what the night sky looks like with the point of view that what's ultimately there is this Ruliad of all possible computations, then that is a necessary object it's unique, once you have the idea of all universal computations you have the Ruliad. Where in Rulial space we happen to exist, the sort of fact that we coherently exist is connected to the fact that we're a limited size in Rulial space just as we are a limited size in physical space. We wouldn't think of ourselves as coexisting as separate entities if we were dispersed and this notion that we're kind of localized in Rulial space..we're taking our simulator hanging by a tiny thread; what does it determine? The Ruliad is necessarily that way, where we are and what we are like as observers of the Ruliad. Can you imagine a kind of hierarchy of observers of the Ruliad so to speak? We're trying to take all that stuff that's going on and compress it down to something that fits in the finite minds we have. We have to equivalence lots of things ignore lots of details and say we just care about the big picture of what's happening. Instead of navigating unpredictable moving objects, we have a scoring system and 30-second timer that add competitive elements; robots earn points by collecting targets while racing not against the obstacles but by racing against the clock.

drawState[arena_, robotPos_, obstacles_, targetPos_, gameState_] := 
  Graphics[{FaceForm[LightGray], EdgeForm[Blue], arena, 
    If[gameState == 
      "playing", {{FaceForm[Green], EdgeForm[Darker@Green], 
       Disk[targetPos, 2]}, {FaceForm[Red], EdgeForm[Darker@Red], 
       Disk[#[[1]], 2] & /@ obstacles}, {FaceForm[Cyan], 
       EdgeForm[Darker@Cyan], Disk[robotPos, 2]}}, {}], 
    If[gameState == "won", {FaceForm[Green], 
      Text[Style["VICTORY!", Bold, 36], Scaled[{0.5, 0.5}]]}, {}], 
    If[gameState == "lost", {FaceForm[Red], 
      Text[Style["GAME OVER!", Bold, 36], Scaled[{0.5, 0.5}]]}, {}]}, 
   ImageSize -> 600, PlotRange -> {{-5, 105}, {-5, 55}}];
DynamicModule[{robotPos = {50, 25}, 
  obstacles = 
   Table[{{RandomReal[{20, 80}], 
      RandomReal[{10, 40}]}, {RandomReal[{-0.8, 0.8}], 
      RandomReal[{-0.8, 0.8}]}}, {8}], 
  targetPos = {RandomReal[{20, 80}], RandomReal[{20, 30}]}, 
  gameState = "playing"}, 
 Dynamic[If[gameState == "playing", 
   obstacles = 
    Map[Function[ob, 
      Module[{newPos = #[[1]] + #[[2]], newVel = #[[2]]}, 
         If[newPos[[1]] < 0 || newPos[[1]] > 100, newVel[[1]] *= -1];
         If[newPos[[2]] < 0 || newPos[[2]] > 50, newVel[[2]] *= -1];
         {newPos, newVel}] &@ob], obstacles];
   If[AnyTrue[obstacles, Norm[robotPos - #[[1]]] < 4 &], 
    gameState = "lost"];
   If[Norm[robotPos - targetPos] < 4, gameState = "won"];];
  EventHandler[
   drawState[Rectangle[{0, 0}, {100, 50}], robotPos, obstacles, 
    targetPos, 
    gameState], {"UpArrowKeyDown" :> 
     If[gameState == "playing", robotPos[[2]] += 3;
      If[robotPos[[2]] > 50, robotPos[[2]] = 50]], 
    "DownArrowKeyDown" :> 
     If[gameState == "playing", robotPos[[2]] -= 3;
      If[robotPos[[2]] < 0, robotPos[[2]] = 0]], 
    "LeftArrowKeyDown" :> 
     If[gameState == "playing", robotPos[[1]] -= 3;
      If[robotPos[[1]] < 0, robotPos[[1]] = 0]], 
    "RightArrowKeyDown" :> 
     If[gameState == "playing", robotPos[[1]] += 3;
      If[robotPos[[1]] > 100, robotPos[[1]] = 100]]}, 
   UpdateInterval -> 0.05, TrackedSymbols :> {}], 
  TrackedSymbols :> {robotPos, obstacles, targetPos, gameState}]]

Green

Thus the simulator now supports distinct game states (playing won lost) with different visual feedback. A new green "goal zone" brings the multi-stage gameplay to a complex game state with the following victory condition: challenge robots to deliver collected items to mimic real-world delivery robot scenarios where objects must be transported to specific locations. And perhaps we could say that it's a different story than somebody's playing a video game and we're just in it. So yeah you're @Carlos Vidal in the project that is, creating a 2d simulator and here's the simulation of an obstacle working with a robot to get picked up.

drawState[arena_Rectangle, robotPosition : {_, _}, 
   targetPosition : {_, _}] := 
  Graphics[{FaceForm[LightGray], EdgeForm[Blue], arena, 
    FaceForm[Pink], EdgeForm[Orange], Rectangle[{96, 46}, {104, 54}], 
    FaceForm[Green], Disk[targetPosition, 5], PointSize[0.05], Cyan, 
    Point[robotPosition], PointSize[0.03], Red, Point[targetPosition],
     Gray, Thick, Dashed, Circle[targetPosition, 5] }];
arena = Rectangle[{0, 0}, {100, 50}];
DynamicModule[{x = 0, y = 25, 
  targetPos = {RandomInteger[{10, 90}], RandomInteger[{10, 40}]}, 
  score = 0, gameStatus = "Playing"}, 
 Dynamic@EventHandler[
   Dynamic[If[
     Norm[{x, y} - targetPos] <= 5 && gameStatus === "Playing", 
     score++;
     targetPos = {RandomInteger[{10, 90}], 
       RandomInteger[{10, 40}]};];
    If[96 <= x <= 104 && 46 <= y <= 54 && gameStatus === "Playing", 
     gameStatus = "WINNER!";
     score += 10;];
    Show[drawState[arena, {x, y}, targetPos], 
     Graphics[{Text[
        Style[StringJoin["Score: ", ToString[score]], Bold, 18, 
         Darker@Red], {10, 45}], 
       Text[Style[gameStatus, Bold, 24, Darker@Green], 
        Scaled[{0.5, 0.5}]], 
       If[gameStatus === "WINNER!", {Yellow, Thick, 
         Circle[Scaled[{0.5, 0.5}], {40, 25}, {0, 2  Pi}]}, {}]}], 
     PlotRange -> {{0, 110}, {0, 60}}]], {"UpArrowKeyDown" :> 
     If[y < 50 && gameStatus === "Playing", y += 2], 
    "DownArrowKeyDown" :> 
     If[y > 0 && gameStatus === "Playing", y -= 2], 
    "LeftArrowKeyDown" :> 
     If[x > 0 && gameStatus === "Playing", x -= 2], 
    "RightArrowKeyDown" :> 
     If[x < 110 && gameStatus === "Playing", x += 2]}]]

Delivery

As the score increases, the targets don't necessarily have to become faster. Instead of using precise collision detection via geometric computation wherein obstacles respawn dynamically to maintain challenge, our demonstrations model how Wolfram Language's symbolic architecture can explain complex robotic interactions. Dynamic and Refresh enable real-time updates and the EventHandler facilitates responsive controls. The geometric computation that we support, accurate physics modeling "provides" a powerful platform for educational exploration of autonomous systems like robots, bridging the gap between theoretical robotics (pathfinding algorithms like A* and rapidly-exploring random trees, sensor simulations like light detection and ranging with or without infrared, energy consumption models and multi-robot coordination)..and the practical implementation that respawns objects dynamically to maintain challenge.

drawState[arena_Rectangle, robotPosition : {_, _}, 
  obstaclePosition : {_, _}] := Graphics[{FaceForm[LightGray],
   EdgeForm[Blue],
   arena,
   FaceForm[Pink],
   EdgeForm[Orange],
   Rectangle[{96, 46}, {104, 54}],
   PointSize[.05],
   Point[robotPosition, VertexColors -> {Cyan}],
   PointSize[0.03],
   Point[obstaclePosition, VertexColors -> {Black, Red}]}]
DynamicModule[{x = 0, y = 25, 
  obstaclePosition = {RandomInteger[100], 25}},
 Dynamic@EventHandler[
   Dynamic[
    If[Norm[{x, y} - obstaclePosition] <= 1, 
     obstaclePosition = {x, y}]; 
    drawState[Rectangle[{0, 0}, {100, 50}], {x, y}, obstaclePosition]],
   {"UpArrowKeyDown" :> (If[y < 50, (y += 1)]),
    "DownArrowKeyDown" :> (If[y > 0, (y -= 1)]),
    "LeftArrowKeyDown" :> (If[x > 0, (x -= 1)]),
    "RightArrowKeyDown" :> (If[x < 100, (x += 1)])}]]

The various robot movements linear or circular, those are the kinds of movements that a robot makes finally @Carlos Vidal you made my fantasy come true: the robot performs a linear routine and if it encounters an obstacle that is the safe area, and I can't wait.

Dynamic 2d Simulator

This is Graphics and ListAnimate functions and the robot can also be controlled using keyboard keys and I'm shouting yeah because of the movement with or without obstacles, in which the robot can continue with its linear routine and create these simulations in the Wolfram Language.

POSTED BY: Dean Gladish

enter image description here -- you have earned Featured Contributor Badge enter image description here Your exceptional post has been selected for our editorial column Staff Picks http://wolfr.am/StaffPicks and Your Profile is now distinguished by a Featured Contributor Badge and is displayed on the Featured Contributor Board. Thank you!

POSTED BY: EDITORIAL BOARD
Reply to this discussion
Community posts can be styled and formatted using the Markdown syntax.
Reply Preview
Attachments
Remove
or Discard

Group Abstract Group Abstract