Ryan's ECE 4960 Site


Lab 10

The Simulator

This lab was dedicated to familiarizing ourselves with the Python Simulation Enviorment what we will use extensively in Lab 11 to simulate grid localization with a Bayes Filter.

The simulation enviornment consists of the simulator itself, which simulates a wheeled robot with an IMU and laser range finder, which is similar to our own physical robots. The simulator also provides odometry information from the simulated IMU's data integrated over time as well as ground truth information of where the robot is actually at. There is a plotter that allows us to plot this odometry and ground truth information along with a plot of the map. It can also plot other information that will be used in later labs.

Additionally, the simulator includes a controller that will allow us to control and interact with our robot. Specifically, it allows us to get our robot's odometry and sensor data, and it allows us to move the robot.

There are several functions that allow us to interact with simulator and plotter described above:

From these functions, I created a few of my own helper functions to help perform the simulator tasks:


          def plot_data():
              pose, gt_pose = cmdr.get_pose()
              cmdr.plot_odom(pose[0], pose[1])
              cmdr.plot_gt(gt_pose[0], gt_pose[1])

          def forward(speed):
              cmdr.set_vel(speed,0)

          # todo: see if changing rotation speed changes the accuracy of the odometry
          def rotate_counter_clockwise():
              cmdr.set_vel(0,2)

          def stop():
              cmdr.set_vel(0,0)
        

Open Loop Control

The first task I did in the simulator was moving the robot around in a square. To accomplish this, I made the robot go forward with a velocity of 1 meters/s for 0.5 seconds, and then made it rotate counter clockwise with an angular velocity of 2 radians/second for 0.76 seconds (found after much trial and error). I then looped this section 5 times with a for loop to form a square. Here is my code for this and a video demonstrating it:


          #open loop control
          cmdr.reset_plotter()
          cmdr.reset_sim()

          if cmdr.sim_is_running() and cmdr.plotter_is_running():
              for i in range(5):
                  forward(1)
                  await asyncio.sleep(0.5)
                  rotate_counter_clockwise()
                  await asyncio.sleep(0.76)
                  plot_data()
              stop()
        

The ground truth and odometry of the robot were pretty far off, but the odometry did manage to record a vaguely squarish shape. Running the the robot multiple times gets roughly the same squarish shape each time, but it is not completely exact.

Closed Loop Control

The next task I did in the simulator was making the robot do closed-loop obstable avoidance with the help of its laser range finder. The algorithm I wrote for this was fairly simple - first the robot checked if the distance from the range finder was less than 0.5 meters. If it is less than 0.5 meters (when it is close to an obstable), it will rotate a slighly obtuse angle. I chose to make it slighly obtuse because I found collisions were frequent if the robot approached a wall almost parallel to the wall, which happened often if the angle wasn't obtuse. If the distance isn't less than 0.5 meters (when it isn't close to an obstacle), the robot will move forward. I found that the slower the robot's linear speed, the less collisions there are. After trial and error I found about 5 meters/second was the fastest speed I could get to while still minimizing collisions. Here is my code for this task and a video demonstrating it:


          #closed loop obstacle avoidance
          cmdr.reset_plotter()
          cmdr.reset_sim()

          while cmdr.sim_is_running() and cmdr.plotter_is_running():
              # can increase distance to reduce collisions maybe
              # can sometimes get stuck, but aleast it doesn't collide
              if(cmdr.get_sensor() < 0.5):
                  #obtuse angle
                  rotate_counter_clockwise();
                  await asyncio.sleep(1)
              else:
                  forward(5)
              plot_data()
        

From the video, it seems that the robot can get fairly close to the wall without colliding, sometimes much less than the 0.5 meter threshold. Also as shown in the video and from tests, the obstacle avoidance doesn't always work. Sometimes the robot runs almost parallel to a wall, which causes its edge to collide with a wall while the robot doesn't know that it is so close to the wall. As stated above, making the rotation always obtuse greatly minimizes these types of collisions, and I could play around with different angles to find the optimal obtuse angle to reduce collisions as much as possible. The robot also sometimes runs head-on into a wall when it is going fast, so a solution could be to either reduce speed or increase the threshold distance.