Pololu TReX motor controller + Arduino: Serial or Analog inputs

Hello all,

I am designing a differential drive robot that uses bump sensors to tell the robot to "reverse, turn, etc." I am using an Arduino Uno and the Pololu TReX Jr to power two dc motors and a third auxiliary motor. I understand how to implement the pushbuttons as "bump sensors," by digitalread()ing the inputs of the buttons. I have gotten small, toy motors running via the buttons using the motor control tutorials and I understand the analogwrite/read functions.

I am a bit confused how to input from the Arduino to the motor controller. I am confused as to whether I want to use the serial TTL communication ports (RX and TX) or if I can simply use the controller in analog mode and use the analogwrite() function to control the inputs to the motor controllers channels. The only example code I've found that pertains specifically to this motor controller, the TReX Jr, is the one provided by Pololu and is in the C# language. I'm assuming I cannot use this code with the Arduino. Also, the motor commands are in the Hexadecimal system, so my other question is how to use the serial communication lines to send these Hex codes. Basically, I need help with the serial communication syntax and if I can use channel 1 and channel 2 in analog mode in order to use the AnalogWrite() function.

Here are links to the TReX Jr user guide, sample code, and command list:

Any help would really be greatly appreciated. I am a novice programmer and understanding the syntax is the biggest difficulty I'm encountering. I posted a similar post in the motor section, but since my questions are a bit broad, and because I got no response, I figured this would be a better location.

you can either control it via serial or with analogWrites/RC transmitter.
-where its says "5 RC or analog inputs" is where you would use analogWrites or RC inputs. to use this you would connect a digital PWM pin to the sig pins on the left side center header, then "+" and "-" from your motor power source and finally GND to your arduino. then jsut use analogWrite(pin,[0 to 255]); for motor control. also note whatthe mix jumpers do here: Pololu - 4.a. Channel Functions

-if you wanted to use serial(TX/RX) from your arduino, you would connect "SO" to RX on the arduino and SI to TX on the arduino(SO and SI are pins in the top right of pic). so, you need to connect GND, TX, and RX from your Arduino to the top right header, then "+" and "-" from your motor power source to the headers on the left side center. note here: http://www.pololu.com/file/download/TReXJr_Commands_v1.2.pdf?file_id=0J12 and Pololu - 5.b. Serial Command Protocols for serial commands.

-it has three modes: RC(like from a hobby transmitter) input, analog(like from your Arduino) and serial. you need to change the mode select jumper on the right side of the pic to choose this.
"When it shorts the left two pins (as shown in the jumper image), the TReX Jr is in RC mode, which means the TReX Jr is expecting RC pulse inputs on its five input channels and that these RC signals will determine the motor outputs. When the jumper shorts the right two mode pins, the TReX Jr is in analog mode; the TReX Jr measures the analog voltages on the five input channels and sets the motor outputs accordingly. When there is no jumper on the three mode pins, the TReX Jr is in serial mode and the serial interface controls the motors"

ill put the serial commands in a different post to make it easier to read.

it says: "For example, if we want to set the auxiliary motor (command 0xF0) to full speed (127) using the Compact protocol, we would send the following byte sequence:
in hex: 0xF0, 0x7F
in decimal: 240, 127"
so i think this could be done as:

Serial.print(240);
Serial.print(127);
or
Serial.print(0x40);
Serial.print(0x7F);

0xC0 – 0xC3: set motor 1
0xC8 – 0xCB: set motor 2
This command takes one data byte and returns nothing. It immediately sets the speed of the
specified motor equal to the data byte and the motor direction based on the two least significant
bits of the command byte. The direction bits work as follows:
00 = brake low (command 0xC0/0xC8)
01 = reverse (command 0xC1/0xC9)
10 = forward (command 0xC2/0xCA)
11 = brake low (command 0xC3/0xCB)
so like:

Serial.print(0xC1); //reverse motor 1
Serial.print(0x7F); //fullspeed

Serial.print(0xC9); //reverse motor 2
Serial.print(0x7F); //fullspeed

Serial.print(0xC2); //forward motor 1
Serial.print(0x7F); //fullspeed

Serial.print(0xCA); //forward motor 2
Serial.print(0x7F); //fullspeed

instead of sending motor speed in hex you could do it like:

Serial.print(0xC1); //reverse motor 1
Serial.print(127, HEX); //fullspeed

so its easier to change value. motor speed is 0 to 127

someone correct me if im wrong

:stuck_out_tongue_closed_eyes: Hell ya!! Thank you for a thorough response!! This is extremely helpful to me. Just read through it quickly before bed, but will definitely be using this to help me!

"if you wanted to use serial(TX/RX) from your arduino, you would connect "SO" to RX on the arduino and SI to TX on the arduino(SO and SI are pins in the top right of pic). so, you need to connect GND, TX, and RX from your Arduino to the top right header, then "+" and "-" from your motor power source to the headers on the left side center."

I'm a bit confused by what you mean the "+" and "-" of the motor power source. I am using a battery connected to the TReX Jr to power the motors and the arduino.

Using this picture of the TRex Jr, I would connect the PWM Arduino pin to the right-most pin labeled "RC/Analog Signal?"

Arduino ground would connect to the leftmost pin labeled "GND" obviously.

The center pin is the 5V out, which can be used to power a RC receiver. Can I use this to power the Arduino or do I need to remove the BEC jumper to disable the 5V output?

This schematic shows it as the "+ - sig" but the previous describes it as the 5V output... I am confused. You are saying to connect the motor power source (a battery), to the "+ -" rc/analog pins. I thought I was to connect the battery terminals to the Vin and GND at the motor input block as shown below:

Thanks again for the help.

i was using the image in my first post which is from the shopping page, not the docs. im guessing the docs are older and have a different picture. i think i miss read how to connect power. that last pic is correct for powering the motors. those three pin headers are for powering the RC receiver, not the motor. i thought all three sets of green wire connector things were for motors, not realizing the center was for the battery.

Hello again,

So I hadn't really tried programming the motor controller because I was busy designing other aspects of our robot and it seemed so simple. Today, I spent a lot of time trying to get this motor working with no luck.

I have a switch which is allows the circuit to be normally HIGH, and when I push the button (momentary switch, not on/off), the circuit is connected to ground. I want the code to work so that when the button is HIGH, the motor is set "forward" (0xC2), at fullspeed (0x7F). I have the LED there to let me know that my switch is working correctly. I'm using the TX line from the arduino to the SI (serial in) of the TREX motor controller. I'm using a 14.4V, 1000mAh Li-Po battery. The default BAUD rate of the TReX Jr motor controller is 19200 bps, but when I tried setting the baud to 19200, Serial.print(19200), nothing happened at all. When I use a BAUD of 9600, the green indicator light on the TREX turns on and off when I push the switch. When the program is uploaded, the motor makes a little noise as if trying to move. Is my battery high enough current? My motor wants 1.2A to run at full power.

Here is my code:

int ledPin = 11;  //pin the led is connected to
int buttonPin = 10;  //pin the switch is connected to
int val = 0;

void setup()
{
  Serial.begin(9600);
  pinMode(ledPin, OUTPUT);   //ledPin (pin 13) is output
  pinMode(buttonPin, INPUT);
}



void loop()
{
  val = digitalRead(buttonPin);  //Read current status of switch

  if (val == HIGH)
  {
    digitalWrite(ledPin, HIGH);
    Serial.print(0xC2); //forward motor 1
    Serial.print(0x7F); //fullspeed
  }

  else
  {
    digitalWrite(ledPin, LOW);
    Serial.print(0xC0);
  }
}

HALP ME!!!

I would think you need to be using Serial.write(), rather than Serial.print().

I was curious about that, but since I was given all the examples using serial.print(), I thought that was it... I'll give that a shot tonight. Thanks.

Hi,

Got the motors running! The problem was because I was using Serial.print

THe newest problem I am having is when running the auxiliary motor, I try to stop the motor temporarily by removing the ground or even the tx line and the motor just keeps on running!! I am confused, but I am sure it has to do with my circuit.

Here is how I am connecting my motors and I'm using the serial communication lines of the Arduino Uno:

Hi all,

i am using the TReX from Pololu for driving the winches on some Access Class Dinghies for disabled sailors at Sailability Gold Coast www.sailabilitygc.org

With some of the help in previous posts i got a start on my code and just sharing the code i have written.

Up to the current point all it should do is

  • set the current limit
  • set the behavior of motors as reaches/passes current limit (shut down motors)
  • Read Joystick
  • Drive TReX out puts proportionally with a dead band to allow for tremors.

Future versions of code will allow for on the fly adjustment of the Dead Band/Current Limits for adjustments to suit weather/racing/leaning persons.

Code looks more complicated than it actually is…due to comprehensive commenting and notes on the Pololu TReX command codes i have stuck in there.

/* written by Tony Matthews for the purpose of
Disabled assist sail winch control
in 303 and liberty Class Access dinghy's

One brushed bidirectional motor drives a main sheet winch,
One brushed bidirectional motor drives a jib sheet (liberty) or rudder (303's, 2.3's)
One brushed motor is a bilge pump, to empty any water that splashes in
Or operate signalling device, horn/light.

Code here in is written by Tony Matthews, whom has TBI.
TBI – Traumatic Brain Injury ...Use at your own risk.
For the benefit of Sailability Gold Coast, Queensland, Australia.

Serial.print is for testing.
tRexSerial.write is the software serial UART to communicate with the TReX.


Notes from Pololu's documentation.
--Motor Current codes --
Code needs one of each ie, current and current limit
0x13: motor 1 current limit (default: 0 – no motor 1 current limit)
0x14: motor 2 current limit (default: 0 – no motor 2 current limit)
0x15: motor 1 current limit proportionality constant P (default: 0x0A)
0x16: motor 2 current limit proportionality constant P (default: 0x0A)

--Acceleration Codes--
Acceleration used over 'set direction' as TReX has in built soft start/stop
Less wear on the winches to have soft starts.
Motor 1 - BiDirectional
0xC4 - Brake Low M1
0xC5 - Reverse M1
0xC6 - Forward M1
0xC7 - Brake low M1

Motor 2 - BiDirectional
0xCC - Brake Low M2
0xCD - Reverse M2
0xCE - Forward M2
0xCF - Brake Low M2

Motor 3 - Single direction only
0xF1 - Accelerate Motor M3

-- Motor speed settings --
May be represented as an integer as the Arduino converts it to HEX automatically (TReX reads HEX)
Must be positive number between 0-127
0 being stopped, 127 full speed 
(Actual speed depends on acceleration logic and current draw V current limit)
eg M3 to full speed would be
tRexSerial.write(0xF1);  //M3
tRexSerial.write(127);  // full speed
*/


//Software serial settings
#include <SoftwareSerial.h>
const int rx = 7; // rx pin of Arduino, SO(serial out)of TRex.
const int tx = 8; // tx pin of Arduino, SI(serial in)of TRex.

SoftwareSerial tRexSerial (rx, tx); // RX to SO of Trex, TX to SI of Trex

// Pot inputs
// Main sheet M1
int mainPin = A0;  //input A0 for mainsheet
int mainVal = 507;  // int to hold mainInput value,  start up in neutral 511
int mainValmapin;
int mainValmapout;


// Jib sheet M2
int jibPin = A1;
int jibVal = 507;
int jibValmapin;
int jibValmapout;

// dead band settings
int deadVal = 200;    // will change to pot values , one for each axis
int midVal = 507;
int fwdVal = (midVal + deadVal);
int revVal = (midVal - deadVal);

// data packet settings
unsigned char data[4];
unsigned long timer = 0;

void setup()
{
  Serial.begin(19200);
  tRexSerial.begin(19200);
  delay (400) ;    // wait for serial to start.

  // Write TReX Motor Settings/Behaviour.
  

  // build M1 data packet for current limit and proportionally constant
  // build M1 current limit packet
  data[0] = (0x80);   // set parameter bit instruction
  data[1] = (0x07);   // TReX id number (if i had more than one, still necessary with only one)
  data[2] = (0x13);   // Parameter id, 0x13 for M1 Current Limit
  data[3] = (7);     // Current limit (desired current limit in milliamps / 150ma / 2 = ( )value)
  // eg, desired current limit 2amps, ergo 2000/150/2=6.66, rounded up to 7
  for (unsigned char i = 0; i < 4; i++)
    tRexSerial.write(data[i]);

  // build M1 Proportionally constant settings packet
  data[0] = (0x80);   // set parameter bit instruction
  data[1] = (0x07);   // TReX id number (if i had more than one, still necessary with only one)
  data[2] = (0x15);   // Parameter id, 0x15 for M1 Proportionally constant current Limit (pccl)
  data[3] = (0);      // Behaviour of PCCL current limit // Proportionally constant 0 (turn motors off if over current)

  for (unsigned char i = 0; i < 4; i++)
    tRexSerial.write(data[i]);

  //Build M2 Parameter settings packets

  //M2 data packet for current limit
  data[0] = (0x80);   // set parameter bit instruction
  data[1] = (0x07);   // TReX id number (if i had more than one, still necessary with only one)
  data[2] = (0x14);   // Parameter id, 0x14 for M2 Current Limit
  data[3] = (7);      // Current limit (desired current limit in milliamps / 150ma / 2 = ( )value)
  // eg, desired current limit 2amps, ergo 2000/150/2=6.66, rounded up to 7
  for (unsigned char i = 0; i < 4; i++)
    tRexSerial.write(data[i]);

  // Build M2 Proportionally constant settings packet

  data[0] = (0x80);   // set parameter bit instruction
  data[1] = (0x07);   // TReX id number (if i had more than one, still necessary with only one)
  data[2] = (0x16);   // Parameter id, 0x15 for M1 Proportionally constant current Limit
  data[3] = (0);      // Behaviour of PCCL  Proportionally constant 0 (turn motors off if over current)

  for (unsigned char i = 0; i < 4; i++)
    tRexSerial.write(data[i]);

  delay (10); // give tRex time to apply settings.

}

void loop () {
  
  // Main sheet control
  mainVal = analogRead(mainPin);
  Serial.print("main = ");
  Serial.print(mainVal);
  if (mainVal > fwdVal)
  {
    // Forward motor A
    mainValmapout = map(mainVal, fwdVal, 1023, 0 , 127); // map reverse speed to return int 0-127
    tRexSerial.write(0xC6); // accelerate motor 1
    tRexSerial.write(mainValmapout); // Analog read val ,mapped, write to software serial.
  }
  else if (mainVal < revVal )
  {
    // Reverse motor A
    mainValmapin = map(mainVal, 0, revVal, 127 , 0); // map reverse speed to return int 0-127
    tRexSerial.write(0xC5); //reverse accelerate motor 1
    tRexSerial.write(mainValmapin); // Analog read val ,mapped, write to software serial.
  }
  else
    tRexSerial.write(0XC4);

  // Jib control
  jibVal = analogRead(jibPin);
  Serial.print(" , jib = ");
  Serial.print(jibVal);
  Serial.println();
  if (jibVal > fwdVal)
  {
    // turn on motor B 'forward'
    jibValmapout = map(jibVal, fwdVal, 1023, 0, 127); // map speed to return positive int 0-127
    tRexSerial.write(0xCE); // accelerate motor 2 forward
    tRexSerial.write(jibValmapout); // Analog read val, mapped write to software serial.
  }
  else if (jibVal < revVal )
  {
    // turn on motor B 'reverse'
    jibValmapin = map(jibVal, 0, revVal, 127 , 0); // map reverse speed to return positive int 0-127
    tRexSerial.write(0xCD); //reverse accelerate motor 2
    tRexSerial.write(jibValmapin); // Analog read val ,mapped, write to software serial.
  }
  else
    tRexSerial.write(0xCC);
}

In testing with no motors connected , just using the LED lights as indicators.
The above code worked…or so i thought.

Hooking motors up it acts odd and i thought at first that the Arduino Analog Read ADC error was messing with the joystick readings.

After a week of messing about with different Joysticks, Ref Voltages, different Arduino boards, many many alterations to code.

…i hooked up my Saleae Logic Analyzer, it was quickly evident the code was the problem and there were no issues with the ADC analog read function of the Arduino Nano V3.0 i was using.

This code below is the physically tested and working copy, there will be tweaks.

  • Pots to alter the current limiting on the fly.
  • Individual pots for each axis.
  • Code to operate M3
/* written by Tony Matthews for the purpose of
Disabled assist sail winch control
in 303 and liberty Class Access dinghy's

One brushed bidirectional motor drives a main sheet winch,
One brushed bidirectional motor drives a jib sheet (liberty) or rudder (303's, 2.3's)
One brushed motor is a bilge pump, to empty any water that splashes in
Or operate signalling device, horn/light.

Code here in is written by Tony Matthews, whom has TBI.
TBI – Traumatic Brain Injury ...Use at your own risk.
For the benefit of Sailability Gold Coast, Queensland, Australia.

Serial.print is for testing.
tRexSerial.write is the software serial UART to communicate with the TReX.


Notes from Pololu's documentation.
--Motor Current codes --
Code needs one of each ie, current and current limit
0x13: motor 1 current limit (default: 0 – no motor 1 current limit)
0x14: motor 2 current limit (default: 0 – no motor 2 current limit)
0x15: motor 1 current limit proportionality constant P (default: 0x0A)
0x16: motor 2 current limit proportionality constant P (default: 0x0A)

--Acceleration Codes--
Acceleration used over 'set direction' as TReX has in built soft start/stop
Less wear on the winches to have soft starts.
Motor 1 - BiDirectional
0xC4 - Brake Low M1
0xC5 - Reverse M1
0xC6 - Forward M1
0xC7 - Brake low M1

Motor 2 - BiDirectional
0xCC - Brake Low M2
0xCD - Reverse M2
0xCE - Forward M2
0xCF - Brake Low M2

Motor 3 - Single direction only
0xF1 - Accelerate Motor M3

-- Motor speed settings --
May be represented as an integer as the Arduino converts it to HEX automatically (TReX reads HEX)
Must be positive number between 0-127
0 being stopped, 127 full speed
(Actual speed depends on acceleration logic and current draw V current limit)
eg M3 to full speed would be
tRexSerial.write(0xF1);  //M3
tRexSerial.write(127);  // full speed

All motor speed/direction/stopped need a speed value to go with them , eg stopped + 0 , forward + 127
*/


//Software serial settings
#include <SoftwareSerial.h>
const int rx = 7; // rx pin of Arduino, SO(serial out)of TRex.
const int tx = 8; // tx pin of Arduino, SI(serial in)of TRex.

SoftwareSerial tRexSerial (rx, tx); // RX to SO of Trex, TX to SI of Trex

// Pot inputs
// Main sheet M1
int mainPin = A0;  //input A0 for mainsheet
int mainVal = 511;  // int to hold main Input value,  start up in neutral 511
int mainValmapin;
int mainValmapout;

// Jib sheet M2
int jibPin = A1;
int jibVal = 511;
int jibValmapin;
int jibValmapout;


// dead band settings
int deadVal = 300;    // will change to pot values , one for each axis
int midVal = 511;
int fwdVal = (midVal + deadVal);
int revVal = (midVal - deadVal);

int zero = 0;    // integer for serial data '0' as 0 is ambiguous as used in a 'serial.write(0)'

// Power/speed variables
// Current limit (desired current limit in milliamp's / 150ma / 2 = ( )value)
// (rounded up) 2amps=7 , 10amps=33
int maxAmps = 2;//Current limit (desired current limit in milliamp's / 150ma / 2 = ( )value)
int overAmpbeh = 0; // over Amp limit behaviour 0=turn motor off
// data packet settings
unsigned char data[4];
unsigned long timer = 0;

void setup()
{
  delay (1000);
  tRexSerial.begin(19200);
  delay (400) ;    // wait for serial to start.

  // Write TReX Motor Settings/Behaviour.


  // build M1 data packet for current limit and proportionally constant
  // build M1 current limit packet
  {
    data[0] = (0x80);   // set parameter bit instruction
    data[1] = (0x07);   // TReX id number (if i had more than one, still necessary with only one)
    data[2] = (0x13);   // Parameter id, 0x13 for M1 Current Limit
    data[3] = (maxAmps);     // Current limit (desired current limit in milliamps / 150ma / 2 = ( )value)
    // eg, desired current limit 2amps, ergo 2000/150/2=6.66, rounded up to 7
    for (unsigned char i = 0; i < 4; i++)
      tRexSerial.write(data[i]);
  }
  delay(10);
  // build M1 Proportionally constant settings packet
  {
    data[0] = (0x80);   // set parameter bit instruction
    data[1] = (0x07);   // TReX id number (if i had more than one, still necessary with only one)
    data[2] = (0x15);   // Parameter id, 0x15 for M1 Proportionally constant current Limit (pccl)
    data[3] = (overAmpbeh);      // Behaviour of PCCL current limit // Proportionally constant 0 (turn motors off if over current)

    for (unsigned char i = 0; i < 4; i++)
      tRexSerial.write(data[i]);
  }
  delay(10);
  //Build M2 Parameter settings packets

  //M2 data packet for current limit
  {
    data[0] = (0x80);   // set parameter bit instruction
    data[1] = (0x07);   // TReX id number (if i had more than one, still necessary with only one)
    data[2] = (0x14);   // Parameter id, 0x14 for M2 Current Limit
    data[3] = (maxAmps);      // Current limit (desired current limit in milliamps / 150ma / 2 = ( )value)
    // eg, desired current limit 2amps, ergo 2000/150/2=6.66, rounded up to 7
    for (unsigned char i = 0; i < 4; i++)
      tRexSerial.write(data[i]);
  }
  delay(10);
  // Build M2 Proportionally constant settings packet
  {
    data[0] = (0x80);   // set parameter bit instruction
    data[1] = (0x07);   // TReX id number (if i had more than one, still necessary with only one)
    data[2] = (0x16);   // Parameter id, 0x15 for M1 Proportionally constant current Limit
    data[3] = (overAmpbeh);      // Behaviour of PCCL  Proportionally constant 0 (turn motors off if over current)

    for (unsigned char i = 0; i < 4; i++)
      tRexSerial.write(data[i]);
  }
  delay (10); // give tRex time to apply settings.

}
void loop () {
  // Main sheet control (M1)
  {
    mainVal = analogRead(mainPin);
    delay(10);

    if (mainVal > fwdVal)   // Forward M1
    {
      mainValmapout = map(mainVal, fwdVal, 1023, 0 , 127); // map speed to return int 0-127
      data [0] = (0xC6); // accelerate motor 1
      data [1] = (mainValmapout);   // Analog read val ,mapped.
      for (unsigned char i = 0; i < 2; i++)
        tRexSerial.write(data[i]);
    }
    else if (mainVal < revVal )  // Reverse M1
    {
      mainValmapin = map(mainVal, 0, revVal, 127 , 0); // map reverse speed to return int 0-127
      data [0] = (0xC5); //reverse accelerate motor 1
      data [1] = (mainValmapin); // Analog read val ,mapped.
      for (unsigned char i = 0; i < 4; i++)
        tRexSerial.write(data[i]);
    }
    else       // stop M1
      tRexSerial.write(0xC7);   // brake low
    tRexSerial.write(zero);   // zero integer value
  }

  //Jib sheet control (M2)
  {
    jibVal = analogRead(jibPin);
    delay(10);

    if (jibVal >= fwdVal)    // Forward M2
    {
      jibValmapout = map(jibVal, fwdVal, 1023, 0, 127); // map speed to return positive int 0-127
      data [0] = (0xCE); // accelerate motor 2 forward
      data [1] = (jibValmapout); // Analog read val, mapped.
      for (unsigned char i = 0; i < 2; i++)
        tRexSerial.write(data[i]);
    }

    else if (jibVal <= revVal )    // Reverse M2
    {
      jibValmapin = map(jibVal, 0, revVal, 127 , 0); // map reverse speed to return positive int 0-127
      data [0] = (0xCD); //reverse accelerate motor 2
      data [1] = (jibValmapin); // Analog read val ,mapped.
      for (unsigned char i = 0; i < 2; i++)
        tRexSerial.write(data[i]);
    }

    else   // brake M2
      tRexSerial.write(0xCF); // brake low
    tRexSerial.write(zero); // zero integer value

  }

}