Using push button with tic driver and I2C

hello, I am trying to control a step motor with a TIC driver. i need to control the accel/decel and all the other functions that tic offers and I2C seems to be the natural choice. my problem is that i am not a coder and very new to this. I have been successful with visuino since it is similar to PLC and ladder logic that I am familiar with; however it does not offer any solutions for tic.
I am hoping that someone is kind enough to create the basic sketch for me and I can then add the tic functions that I need to the sketch using the help files for the tic library. this is what needs to happen:

when a button is pushed, the step motor moves a specific number of steps at specific speed / accel /decel. when that button is pushed again, the motor reverses and goes back to its original position. IMPORTANT, the button does not do anything while the motor is in motion.

thank you in advance

Hello.

It is typically beyond the scope of our technical support to take programming requests, but in this case you can get what you want with some pretty minor edits to the I2CPositionControl.ino example from our Tic library for Arduino. For handling button presses, I recommend our pushbutton library for Arduino. Starting with the I2CPositionControl.ino example as a base, the main loop would look something like this instead:

void loop()
{
  //wait for button to be pressed
  while(!button.getSingleDebouncedPress()){
    delayWhileResettingCommandTimeout(10);
   }

  // Tell the Tic to move to position 100, and wait until it gets there
  tic.setTargetPosition(100);
  waitForPosition(100);

  //wait for button to be pressed again
  while(!button.getSingleDebouncedPress()){
    delayWhileResettingCommandTimeout(10);
   }

  // Tell the Tic to move to position -100, and wait until it gets there
  tic.setTargetPosition(-100);
  waitForPosition(-100);
}

If you do not need the speed and acceleration/deceleration to change throughout the sketch, you can simply configure them in the “input and motor settings” tab of the Tic Control Center. If you want to specify different values for each movement, you can add setMaxSpeed(), setMaxAccel(), and setMaxDecel() commands before the setTargetPosition() commands.

If you try putting that code together and have problems, could you post a copy of what you have so far and a description of what happens when you try to run it?

Brandon

Hi Brandon,

thanks for the reply and it was a great help to get me started. I followed your instructions and I was able to compile a sketch without errors and then send it to my arduino, see below. however, I am getting some unexpected results:

If I press the button once, nothing happens.
when i press the button again, the motor moves the 100 steps like it is supposed to.
After that, nothing happens no matter how many times I press the button.
I have to reboot the arduino and then i can repeat the process above.

your help is much appreciated.

// This example shows how to send I2C commands to the Tic
// Stepper Motor Controller to control the position of a Stepper
// Motor.
//
// The Tic's control mode must be set to "Serial/I2C/USB".  The
// serial device number must be set to its default value of 14.
//
// If you have sent a De-energize command to the Tic, for example
// by clicking "De-energize" in the Tic Control Center, you will
// need to undo that by clicking "Resume" or power-cycling the
// Tic.
//
// Please see https://github.com/pololu/tic-arduino for details
// on how to make the connections between the Arduino and the
// Tic.

#include <Tic.h>
#include <Pushbutton.h>
#define BUTTON_PIN 7
Pushbutton button(BUTTON_PIN);

TicI2C tic;

void setup()
{
  // Set up I2C.
  Wire.begin();

  // Give the Tic some time to start up.
  delay(20);

  // Set the Tic's current position to 0, so that when we command
  // it to move later, it will move a predictable amount.
  tic.haltAndSetPosition(0);

  // Tells the Tic that it is OK to start driving the motor.  The
  // Tic's safe-start feature helps avoid unexpected, accidental
  // movement of the motor: if an error happens, the Tic will not
  // drive the motor again until it receives the Exit Safe Start
  // command.  The safe-start feature can be disbled in the Tic
  // Control Center.
  tic.exitSafeStart();
  
}

// Sends a "Reset command timeout" command to the Tic.  We must
// call this at least once per second, or else a command timeout
// error will happen.  The Tic's default command timeout period
// is 1000 ms, but it can be changed or disabled in the Tic
// Control Center.
void resetCommandTimeout()
{
  tic.resetCommandTimeout();
}

// Delays for the specified number of milliseconds while
// resetting the Tic's command timeout so that its movement does
// not get interrupted by errors.
void delayWhileResettingCommandTimeout(uint32_t ms)
{
  uint32_t start = millis();
  do
  {
    resetCommandTimeout();
  } while ((uint32_t)(millis() - start) <= ms);
}

// Polls the Tic, waiting for it to reach the specified target
// position.  Note that if the Tic detects an error, the Tic will
// probably go into safe-start mode and never reach its target
// position, so this function will loop infinitely.  If that
// happens, you will need to reset your Arduino.
void waitForPosition(int32_t targetPosition)
{
  do
  {
    resetCommandTimeout();
  } while (tic.getCurrentPosition() != targetPosition);
}

void loop()
{
  //wait for button to be pressed
  while(!button.getSingleDebouncedPress()){
    delayWhileResettingCommandTimeout(10);
   }

  //wait for button to be pressed again
  while(!button.getSingleDebouncedPress()){
    delayWhileResettingCommandTimeout(10);
   }

  // Tell the Tic to move to position -100, and wait until it gets there
  tic.setTargetPosition(-100);
  waitForPosition(-100);
}

Hello.

It looks like you are missing the tic.setTargetPosition(100) and waitForPosition(100) commands between the two button presses. So, the code right now is just trying to set the target position to -100 every time the button is pressed twice, but since the stepper motor is already at that position, it only moves the first time through. Could you try adding those commands and seeing if that fixes the problem? If not, could you describe what happens and post your updated program?

Brandon

Brandon,

thank you very much, you have helped me to understand what is going on much better. I am now able to control the step motor through TIC with I2C. next step is to do the same for multiple motors. I understand that I need to give different TIC different device numbers but I have not idea how to identify them in the sketch.

thank you again,

I am glad you got it working! To control multiple Tic controllers, you can give each one a unique device number, then use those device numbers when instantiating the object for each. You can see how this is done in the I2CMulti.ino example sketch from the library.

In that example, you can see that one object, tic1, is declared for a Tic with a device number of 14 . So, the Tic with a device number of 14 will only respond to the commands that start with tic1.. Similarly, tic2 is used in that example to send commands to the Tic with a device number of 15.

Brandon

OK, we are almost there. I have multiple drivers connected. Next step, I would like to send the motors to the positions that are set through the Tic Control Center instead of calling the number of steps in the code when the button is pushed. is that possible?

thank you again,

I am not sure I understand what you are describing. The setTargetPosition() command specifies the position you want the motor to go to (the same way the “Set target” slider does in the Tic Control Center), and not the number of steps for the motor to take. If that does not answer your question could you explain in detail how you want it to work compared to how it is working right now?

Brandon

Brandon,

thank you for clarification and I think I am beginning to understand. I have a question of the waitForPosition(100). it is fine when we are dealing with one motor. how do it make sure all three motors have reached their position after I send the SetTargetPosition(100) to tic1 and tic2 and tic3.

 // Tell the tics to move to position 100, and wait until it gets there
  tic1.setTargetPosition(100);
  tic2.setTargetPosition(100);
  tic3.setTargetPosition(100);
  waitForPosition(100); 

I guess my problem is broader than i thought. it works when i have two motors in the code but a third motor messes it up. when i add the third motor and push the button, all three motor move once then nothing happens

thank you for your help,

// This example shows how to send I2C commands to the Tic
// Stepper Motor Controller to control the position of a Stepper
// Motor.
//
// The Tic's control mode must be set to "Serial/I2C/USB".  The
// serial device number must be set to its default value of 14.
//
// If you have sent a De-energize command to the Tic, for example
// by clicking "De-energize" in the Tic Control Center, you will
// need to undo that by clicking "Resume" or power-cycling the
// Tic.
//
// Please see https://github.com/pololu/tic-arduino for details
// on how to make the connections between the Arduino and the
// Tic.

#include <Tic.h>
#include <Pushbutton.h>
#define BUTTON_PIN 7
Pushbutton button(BUTTON_PIN);


TicI2C tic1(14);
TicI2C tic2(15);
TicI2C tic3(16);

void setup()
{
  // Set up I2C.
  Wire.begin();

  // Give the tic1 some time to start up.
  delay(20);

  // Set the tic1's current position to 0, so that when we command
  // it to move later, it will move a predictable amount.
  tic1.haltAndSetPosition(0);
  tic2.haltAndSetPosition(0);
  tic3.haltAndSetPosition(0);
  

  // Tells the tic1 that it is OK to start driving the motor.  The
  // tic1's safe-start feature helps avoid unexpected, accidental
  // movement of the motor: if an error happens, the tic1 will not
  // drive the motor again until it receives the Exit Safe Start
  // command.  The safe-start feature can be disbled in the tic1
  // Control Center.
  tic1.exitSafeStart();
  tic2.exitSafeStart();
  tic3.exitSafeStart();
  
  
}

// Sends a "Reset command timeout" command to the tic1.  We must
// call this at least once per second, or else a command timeout
// error will happen.  The tic1's default command timeout period
// is 1000 ms, but it can be changed or disabled in the tic1
// Control Center.
void resetCommandTimeout()
{
  tic1.resetCommandTimeout();
  tic2.resetCommandTimeout();
  tic3.resetCommandTimeout();
}

// Delays for the specified number of milliseconds while
// resetting the tic's command timeout so that its movement does
// not get interrupted by errors.
void delayWhileResettingCommandTimeout(uint32_t ms)
{
  uint32_t start = millis();
  do
  {
    resetCommandTimeout();
  } while ((uint32_t)(millis() - start) <= ms);
}

// Polls the tic1, waiting for it to reach the specified target
// position.  Note that if the tic detects an error, the tic will
// probably go into safe-start mode and never reach its target
// position, so this function will loop infinitely.  If that
// happens, you will need to reset your Arduino.
void waitForPosition(int32_t targetPosition)
{
  do
  {
    resetCommandTimeout();
  } 
  while (tic1.getCurrentPosition() != targetPosition);


}

void loop()
{
  //wait for button to be pressed
  while(!button.getSingleDebouncedPress()){
    delayWhileResettingCommandTimeout(10);
   }
   
 // Tell the tics to move to position 100, and wait until it gets there
  tic1.setTargetPosition(100);
  tic2.setTargetPosition(100);
  tic3.setTargetPosition(100);
  waitForPosition(100); 



  //wait for button to be pressed again
  while(!button.getSingleDebouncedPress()){
    delayWhileResettingCommandTimeout(10);
   }

  // Tell the tic1 to move to position 0, and wait until it gets there
  tic1.setTargetPosition(0);
  tic2.setTargetPosition(0);
  tic3.setTargetPosition(0);
  waitForPosition(0);

}

I do not see any obvious reason that your program would lock up after one button press. You might try printing some information to the serial monitor to try to get a better idea of what is going on. For example, you could add the following serial commands to your waitForPosition() function so you can see if it is getting stuck in that loop (i.e. if tic1.getCurrentPosition() is returning the wrong value or never reaching the target position):

void waitForPosition(int32_t targetPosition)
{
  do
  {
    Serial.print("tic1 current position: ");  Serial.println(tic1.getCurrentPosition());
    Serial.print("Target position: ");  Serial.println(targetPosition);
    Serial.println();
    resetCommandTimeout();
  } 
  while (tic1.getCurrentPosition() != targetPosition);
}

Brandon

Brandon,
I think i know what was happening. i was running out of current. adjusting the max current settings fixed the problem until i find a better power supply.

thank you,

I am glad to hear you found the problem and were able to get it working. Thank you for following-up to let us know.

By the way, your waitForPosition() function currently only checks that tic1 has reached the target position, and not tic2 or tic3. If you want it to make sure all 3 Tics get to the target position before continuing, you can change it to something like this:

void waitForPosition(int32_t targetPosition)
{
  do
  {
    resetCommandTimeout();
  } 
  while (tic1.getCurrentPosition() != targetPosition ||
         tic2.getCurrentPosition() != targetPosition ||
         tic3.getCurrentPosition() != targetPosition);

}

Brandon

Brandon,

What would that code look like if I wanted to specify three different positions for you he motor?

Thank you,

Farid Taghaboni

Technical Sales Director - PERMCO USA
Business Development Director - PERMCO INDIA

You could either use a separate function for each Tic, or combine it all in one large function depending on how you want it to work. If you want a single function that waits for all three Tics to get to their commanded positions, you could use something like this:

void waitForPosition(int32_t tic1TargetPosition, int32_t tic2TargetPosition, int32_t tic3TargetPosition)
{
  do
  {
    resetCommandTimeout();
  } 
  while (tic1.getCurrentPosition() != tic1TargetPosition ||
         tic2.getCurrentPosition() != tic2TargetPosition ||
         tic3.getCurrentPosition() != tic3TargetPosition);
}

Please note that there are now 3 arguments to that function that need to be specified when you call it, one for each Tic. So, for example, the code in your main loop might look something like this:

  tic1.setTargetPosition(100);
  tic2.setTargetPosition(0);
  tic3.setTargetPosition(-100);
  waitForPosition(100, 0 , -100); 

Brandon

Perfect, it is doing what I need it to do. now I am going to play with controlling the acceleration / deceleration for individual motors to smooth out the motion.

thank you very much,

1 Like