Announcement

Collapse

Technology Forum Has Moved!

The FIRST Tech Challenge Technology forum has moved to a new location! Please take a look at our forum blog for links and instructions on how to access the new forum.

The official blog of the FIRST Tech Challenge - a STEM robotics programs for students grades 7-12.


Note that volunteers (except for FTA/WTA/CSA will still access their role specific forum through this site. The blog also outlines how to access the volunteer forums.
See more
See less

Help with arduinos and the FTC control system

Collapse
X
 
  • Filter
  • Time
  • Show
Clear All
new posts

  • Help with arduinos and the FTC control system

    This year, my team had an idea for a different method of running an autonomous that we would like to try out. It involves using an Arduino Uno to monitor sensor values and then report them back to the robot controller phone via an I2C connection and the CDI. I have found on the forum that Arduinos are illegal in FTC because they count as a separate computer. I was looking for some clarification with this rule. Does the way that the Arduino is used change that ruling? In our case, it would function as a slave to the robot controller. Any help with this would be much appreciated. We are really wanting to go a different route with our autonomous and we think this would be a good option if we can make sure it is legal.

    Thank you,
    Ben

  • #2
    What is/are the reason(s) behind wanting to use the Arduino to monitor sensors? Was it because of some short comings of the Android phone or FTC SDK? There may be alternatives to solve your issues than going with an Arduino. With an Arduino, you still need to interface with the Android phone via I2C. So if your issues are with the performance of I2C support in the FTC SDK, you may still have problems. With the new REV hub and possibly fixes in the FTC SDK, it may no longer be an issue. So tell us your issues.

    Comment


    • #3
      We plan on using a lot of different sensors to create an autonomous that is capable of correcting in changes in environment. For example, if an opposing robot parked in the path of our teams robot during the autonomous period, our robot would be able to problem solve an alternative route to still end up in its desired location. From what I understand of how the FTC SDK works, the code runs in a linear sort of fashion meaning that it can check one sensor, then the next, and then the next, and so on... With how we want to set this up, every sensor or set of sensors needs to be reliably checked every time it refreshes so that changes are detected at a moments notice. I was hoping this would avoid issues like an obstacle in front of the robot, but the robot doesn't identify it because it hasn't run the code for that sensor yet. My thinking behind using an arduino was that it would be dedicated to a sensor and when certain criteria is met, it communicates that back to the cell phone which is continuously running a loop that runs while no criteria from the arduino has been met. Its a concept that follows the idea of division of labor. I want to use an arduino to handle the sensors and when an issue comes up, it tells the robot controller which can decide what to do next. I just can't see a logical way of checking every sensor at the same time if the code is only able to check each sensor individually. It's not necessarily that I have a problem with getting the FTC SDK to work correctly, but unless there's a way to have the phone multitask different sets of code, this seemed like it would be the most efficient method.

      Comment


      • #4
        team6181, your team's code would still have to check the Arduino at some point via the exact same ways that the sensors are read, so the way I see it you still have two options for designing your code with or without the Ardunio.

        You can use the main OpMode control loop to drive a state machine that adjusts accordingly to sensor input (which is what it sounds like you are building), then either fetch the sensors' values during each loop and calculate the course of action or spin up a new thread to poll the sensors then fire a callback that adjusts your OpMode control loop's parameters. Keep in mind with the latter option, you need to be sure your OpMode loop is thread-safe (you can read up on that subject), however you should prefer the former option unless the sensor read performance is really an issue for you. Even then, since I haven't brushed up on the latest and greatest FTC SDK I2C APIs, I can't be sure that the system can't fire the callbacks for you.

        Comment


        • #5
          Originally posted by dmssargent View Post
          team6181, your team's code would still have to check the Arduino at some point via the exact same ways that the sensors are read, so the way I see it you still have two options for designing your code with or without the Ardunio.

          You can use the main OpMode control loop to drive a state machine that adjusts accordingly to sensor input (which is what it sounds like you are building), then either fetch the sensors' values during each loop and calculate the course of action or spin up a new thread to poll the sensors then fire a callback that adjusts your OpMode control loop's parameters. Keep in mind with the latter option, you need to be sure your OpMode loop is thread-safe (you can read up on that subject), however you should prefer the former option unless the sensor read performance is really an issue for you. Even then, since I haven't brushed up on the latest and greatest FTC SDK I2C APIs, I can't be sure that the system can't fire the callbacks for you.
          If I were to go with the first option, would the speed that the loop can fetch each sensor be fast enough to react to a sudden change? Also, I managed to get an object tracking camera called pixy to work with the FTC SDK and we plan on using that this coming season as well. It would require a constant loop to watch the values and I don't think it would work good enough if it were in the main loop with everything else. If I were just going to code everything, how would you set up a loop dedicated to only the camera, and also a loop to run everything else during autonomous?

          Comment


          • #6
            It sounds like your issue is a multi-tasking issue. If you structure your code correctly either by using multiple threads or a state machine reading multiple sensors, the Android phone can handle it. Even if you decided to use Arduino, you still have similar issues. In Arduino, it doesn't have a sophisticated OS supporting multiple threads, so you have to read one sensor at a time anyway. So you might as well do it on the Android phone to skip the complexity of talking to the Arduino over I2C which could be a separate thread anyway.

            Comment


            • #7
              Here is a demo class that demonstrates using multiple threads and some various ways to share a value between the threads.

              Code:
              public class ConcurrencyShowcase extends OpMode {
                  private final ExecutorService service;
                  private final Object stateLock;
                  private volatile RunState runState;
                  private volatile boolean updateTelemetry = true;
                  private final CameraLoop cameraLoop;
                  private final SensorUpdateLoop sensorUpdateLoop;
              
                  public ConcurrencyShowcase() {
                      this.stateLock = new Object();
                      runState = RunState.CTOR;
                      service = Executors.newCachedThreadPool();
                      cameraLoop = new CameraLoop();
                      sensorUpdateLoop = new SensorUpdateLoop(new Runnable() {
                          @Override
                          public void run() {
                              updateTelemetry = !updateTelemetry;
                          }
                      });
              
                      service.submit(cameraLoop);
                      service.submit(sensorUpdateLoop);
                  }
              
                  @Override
                  public void init() {
                      updateRunState(RunState.INIT);
                  }
              
                  @Override
                  public void loop() {
                      updateRunState(RunState.LOOP);
                      // todo: demo code
                      telemetry.addData("SENSOR_INIT", sensorUpdateLoop.hasInited).setRetained(true);
                      if (updateTelemetry) {
                          telemetry.addData("COUNTER", cameraLoop.count);
                          telemetry.addData("FIRE", sensorUpdateLoop.fire);
                      } else {
                          telemetry.clear();
                      }
                  }
              
                  @Override
                  public void stop() {
                      updateRunState(RunState.STOP);
                      if (service.isShutdown()) {
                          try {
                              if (!service.awaitTermination(30, TimeUnit.MILLISECONDS)) {
                                  throw new RuntimeException("timeout waited for shutdown");
                              }
                          } catch (InterruptedException e) {
                              Thread.currentThread().interrupt();
                          }
                      }
                  }
              
                  private void updateRunState(RunState state) {
                      runState = state;
                      synchronized (stateLock) {
                          runState.notifyAll();
                      }
                  }
              
                  private void waitForState(RunState state) {
                      while (!Thread.currentThread().isInterrupted() && runState != state) {
                          try {
                              stateLock.wait();
                          } catch (InterruptedException e) {
                              Thread.currentThread().interrupt();
                          }
                      }
                  }
              
                  private void sleep(long millis) {
                      try {
                          Thread.sleep(millis);
                      } catch (InterruptedException e) {
                          Thread.currentThread().interrupt();
                      }
                  }
              
                  private final class CameraLoop implements Runnable {
                      volatile int count = 0;
              
                      @Override
                      public void run() {
                          synchronized (stateLock) {
                              waitForState(RunState.LOOP);
                              while (runState == RunState.LOOP && !Thread.currentThread().isInterrupted()) {
                                  // todo: demo code, your code here
                                  count++;
                                  if (count > 100) count = 0;
                                  sleep(100);
                              }
                          }
                      }
                  }
              
                  private final class SensorUpdateLoop implements Runnable {
                      volatile boolean hasInited = false;
                      volatile boolean fire = false;
                      private final Runnable fireCallback;
              
                      private SensorUpdateLoop(Runnable fireCallback) {
                          this.fireCallback = fireCallback;
                      }
              
                      @Override
                      public void run() {
                          // todo: demo code, replace with your own
                          waitForState(RunState.INIT);
                          hasInited = true;
                          waitForState(RunState.LOOP);
                          while (runState == RunState.LOOP && !Thread.currentThread().isInterrupted()) {
                              fire = !fire;
                              if (fire && fireCallback != null) {
                                  fireCallback.run();
                              }
                              sleep(1000);
                          }
                      }
                  }
              
                  private enum RunState {
                      CTOR, INIT, LOOP, STOP
                  }
              }
              I would also recommend reading the following tutorial from Oracle about Java concurrency: https://docs.oracle.com/javase/tutor...l/concurrency/

              Comment


              • #8
                Originally posted by dmssargent View Post
                Here is a demo class that demonstrates using multiple threads and some various ways to share a value between the threads.

                Code:
                public class ConcurrencyShowcase extends OpMode {
                private final ExecutorService service;
                private final Object stateLock;
                private volatile RunState runState;
                private volatile boolean updateTelemetry = true;
                private final CameraLoop cameraLoop;
                private final SensorUpdateLoop sensorUpdateLoop;
                
                public ConcurrencyShowcase() {
                this.stateLock = new Object();
                runState = RunState.CTOR;
                service = Executors.newCachedThreadPool();
                cameraLoop = new CameraLoop();
                sensorUpdateLoop = new SensorUpdateLoop(new Runnable() {
                @Override
                public void run() {
                updateTelemetry = !updateTelemetry;
                }
                });
                
                service.submit(cameraLoop);
                service.submit(sensorUpdateLoop);
                }
                
                @Override
                public void init() {
                updateRunState(RunState.INIT);
                }
                
                @Override
                public void loop() {
                updateRunState(RunState.LOOP);
                // todo: demo code
                telemetry.addData("SENSOR_INIT", sensorUpdateLoop.hasInited).setRetained(true);
                if (updateTelemetry) {
                telemetry.addData("COUNTER", cameraLoop.count);
                telemetry.addData("FIRE", sensorUpdateLoop.fire);
                } else {
                telemetry.clear();
                }
                }
                
                @Override
                public void stop() {
                updateRunState(RunState.STOP);
                if (service.isShutdown()) {
                try {
                if (!service.awaitTermination(30, TimeUnit.MILLISECONDS)) {
                throw new RuntimeException("timeout waited for shutdown");
                }
                } catch (InterruptedException e) {
                Thread.currentThread().interrupt();
                }
                }
                }
                
                private void updateRunState(RunState state) {
                runState = state;
                synchronized (stateLock) {
                runState.notifyAll();
                }
                }
                
                private void waitForState(RunState state) {
                while (!Thread.currentThread().isInterrupted() && runState != state) {
                try {
                stateLock.wait();
                } catch (InterruptedException e) {
                Thread.currentThread().interrupt();
                }
                }
                }
                
                private void sleep(long millis) {
                try {
                Thread.sleep(millis);
                } catch (InterruptedException e) {
                Thread.currentThread().interrupt();
                }
                }
                
                private final class CameraLoop implements Runnable {
                volatile int count = 0;
                
                @Override
                public void run() {
                synchronized (stateLock) {
                waitForState(RunState.LOOP);
                while (runState == RunState.LOOP && !Thread.currentThread().isInterrupted()) {
                // todo: demo code, your code here
                count++;
                if (count > 100) count = 0;
                sleep(100);
                }
                }
                }
                }
                
                private final class SensorUpdateLoop implements Runnable {
                volatile boolean hasInited = false;
                volatile boolean fire = false;
                private final Runnable fireCallback;
                
                private SensorUpdateLoop(Runnable fireCallback) {
                this.fireCallback = fireCallback;
                }
                
                @Override
                public void run() {
                // todo: demo code, replace with your own
                waitForState(RunState.INIT);
                hasInited = true;
                waitForState(RunState.LOOP);
                while (runState == RunState.LOOP && !Thread.currentThread().isInterrupted()) {
                fire = !fire;
                if (fire && fireCallback != null) {
                fireCallback.run();
                }
                sleep(1000);
                }
                }
                }
                
                private enum RunState {
                CTOR, INIT, LOOP, STOP
                }
                }
                I would also recommend reading the following tutorial from Oracle about Java concurrency: https://docs.oracle.com/javase/tutor...l/concurrency/
                Thank you for this code, it helps to see how to set up that machine. I haven't really ever done much with multiple threads which is why it's a little daunting to me. I don't fully understand how that works. I'll do some playing around with this code this week and see if I can use it to get what I want to do with our test robot. Just for clarification, is it illegal to use an arduino at all? From what you guys have said, it looks like the use of one is discouraged and it would be easier to go with out using one, but I just wanted to know for future reference if they are allowed or if there is certain instances where they would be allowed. Thank you again for the help with this. My team and I really appreciate it. I'll run some tests with it and let you guys know what happens. If this does what I want, that would be awesome and would save us the time of having to setup an arduino.

                Ben

                Comment


                • #9
                  I strongly discourage the use of the Arduino, because it was not allowed for last season, and probably won't be allowed this season. However, the Part 1 of the FTC Game Manual (it usually comes out in early-mid July) should be sometime out soon, so check that manual when it is released.

                  Comment


                  • #10
                    Okay, we will keep that in mind. I will try to work with the multi threading in the code to accomplish what I'm trying to do.

                    Thank you again.
                    Ben

                    Comment


                    • #11
                      Originally posted by team6181 View Post

                      Thank you for this code, it helps to see how to set up that machine. I haven't really ever done much with multiple threads which is why it's a little daunting to me. I don't fully understand how that works. I'll do some playing around with this code this week and see if I can use it to get what I want to do with our test robot. Just for clarification, is it illegal to use an arduino at all? From what you guys have said, it looks like the use of one is discouraged and it would be easier to go with out using one, but I just wanted to know for future reference if they are allowed or if there is certain instances where they would be allowed. Thank you again for the help with this. My team and I really appreciate it. I'll run some tests with it and let you guys know what happens. If this does what I want, that would be awesome and would save us the time of having to setup an arduino.

                      Ben
                      From what you described, I don't think Arduino is the right solution for you anyway. However, if you haven't dealt with multi-threaded programming before, you may want to look into doing multi-tasking with cooperative multi-tasking (i.e. using a single thread to do multiple tasks). Dealing with multi-thread synchronization, deadlock and livelock is not simple. You will have many subtle bugs that you may not even know why it failed and what caused them. If you are interested in cooperative multitasking, I can walk you through the concept.

























                      Comment

                      Working...
                      X