Control Motors with PC Input

Hello to All and thanks in advance for any help. The end goal for my project is to control 2 motors using a
wireless xbox controller connected to my PC. I'm new to the Arduino and programming world, so please forgive me for my ignorance. I'm using the Arduino Uno and the 2A DFRobot Motor Shield to control the motors. I understand what I have to do, I just don't know how to do it.

For now what I need to figure out is how to write and/or find a software for my PC that will send user input from the computers keyboard to the COM4 port. From there I need to again find and/or write a sketch for Arduino that will accept that input and direct the motors either forward or reverse, using the W and S keys and/or the up and down arrows.

I have been googling like crazy trying to figure out where to start, but I feel I'm just as lost as when I started. If anyone knows of something like this that already exists, or has done something like it in the past, any information would be a great help.

As a side note/question, Ive noticed that running my Uno and motorshield for a while really causes it to heat up, is it possible to also run a fan or 2 off of the arduino as well as the motors? If so I can just build a lexan casing and add fans to cool it.

Did you already read this: http://arduino.cc/playground/Main/InterfacingWithHardware#Physical_Mechanical

Have you looked through the Interfacing With Software section of the Arduino Playground?

Also, while it would be possible to run the fans off the 5 VDC from the Arduino, it will be an extra current draw on the less than 0.5 A current limit of standard Arduino boards. If this is going to be interfacing with the computer, why not wire up an appropriate connector and run the fans, and perhaps the motors, from the computer's PSU?

Udo, I have glanced at a few things in there but am not sure what I can use or how to use it, I did find this however, http://home.online.no/~togalaas/ardubot/ would I be able to use this code to control the motors and then adapt the Wii code to use the wireless adapter for the xbox controller?

Far-Seeker, that's an awesome idea!!!! as for the software playground... what would I use out of there? There is so much information and so many different programs to use.

Its funny how an idea can seem so easy until you start actually doing it... I think I may have gotten way over my head...

LunchusBoxious:
Far-Seeker, that's an awesome idea!!!! as for the software playground... what would I use out of there? There is so much information and so many different programs to use.

Thanks, unfortunately I haven't had an excuse to really mess around with interfacing and Arduino with PC software (other than the Arduino IDE, of course). However, since it's part of the standard libraries that come with the IDE, Firmata should have a decent base of previously existing code. You are correct that there are a lot of options, which is probably why a whole section of the Forum is devoted to the topic. You might want to ask for advice on software interfacing there as well.

Edit: Oh and please don't try to directly power your Arduino from your computer's PSU! Without additional hardware, a normal computer PSU doesn't have a means to limit the current at a safe level for the Arduino. This thread discussing how to use an ATX power supply as the basis of a benchtop power supply goes into more of the details...

I didn't even see that section of the forum.... I guess that would have been a good place to start... Thank you so much for the help.

If you were just beginning the project, and were only considering using the Arduino to control the motors, it might have been simpler to use a motor controller with a USB input, so you could control it directly from the PC, such as Pololu Simple Motor Controllers.

However, since you have the Arduinos, it is more a matter of how to use them. In general, you write a small program on your PC, that opens up COM4, and reads from standard input and writes to COM4. For example, I believe PuTTY under Windows can do this: http://www.ehow.com/how_8733462_use-putty-serial-connection.html.

MichaelMeissner:
If you were just beginning the project, and were only considering using the Arduino to control the motors, it might have been simpler to use a motor controller with a USB input, so you could control it directly from the PC, such as Pololu Simple Motor Controllers.

Well it looks like LunchusBoxious will have to add extra functionality to justify using the Arduino... Like displaying the output level of each motor on a LED bar graph and/or LCD. :wink:

For the Controller on this project http://home.online.no/~togalaas/ardubot/ if I were to buy a third party Nunchuk, would it still work? or does it have to be the Wii branded one?

LunchusBoxious:
For the Controller on this project http://home.online.no/~togalaas/ardubot/ if I were to buy a third party Nunchuk, would it still work? or does it have to be the Wii branded one?

If the third party 'chuck uses the same control signals as an official one, like any decent copy should, it won't make any difference. Even if it doesn't it could be made to work, but you couldn't use existing libraries and instead would have to do some reverse engineering.

Why can't anything be easy? lol... I think I might just buy it and try it... at least with this I don't have to run it through the computer, therefore making my job that much easier. I can't wait to finish this project so I can start another one... I'll keep you updated and let you know if it works.

Here's a question for you, what do I have to change within this code since I'll be using my own motors with a motor shield rather than the Ardubot PCB. I have read over it, and well to me at this point in my Arduino career, looks like Japanese... I know I have to change the pins that the motor is connected to, but is there anything else??

const byte WII_IDENT_LEN = 6;
const byte WII_TELEGRAM_LEN = 6;
const byte WII_NUNCHUCK_TWI_ADR = 0x52;

const byte right1 = 9; // Right motor control 1
const byte right2 = 6; // Right motor control 2

const byte left1 = 5; // Left motor control 1
const byte left2 = 3; // Left motor control 2

const byte joy_x_mid = 133;    // Sample value
const byte joy_y_mid = 130;    // Sample value

const int acc_x_mid = 512;
const int acc_y_mid = 512;

int button_state = 1; // variable for reading the Z-button status
int led_state = 0;    // variable containing LED status
int change = 0;

#include <Wire.h>

byte outbuf[WII_TELEGRAM_LEN]; // array to store arduino output
int cnt = 0;

void setup ()
{

  Wire.begin(); // initialize i2c

  pinMode(right1, OUTPUT); 
  pinMode(right2, OUTPUT); 
  pinMode(left1, OUTPUT); 
  pinMode(left2, OUTPUT);
  pinMode(13, OUTPUT);

  nunchuck_init(0); // send the initialization handshake
}

// params:
// timeout: abort when timeout (in ms) expires, 0 for unlimited timeout
// return: 0 == ok, 1 == timeout
byte nunchuck_init (unsigned short timeout)
{
  byte rc = 1;
  unsigned long time = millis();
  do
  {
    Wire.beginTransmission (WII_NUNCHUCK_TWI_ADR); // transmit to device 0x52
    Wire.send (0xF0); // sends memory address
    Wire.send (0x55); // sends data. 
    if(Wire.endTransmission() == 0) // stop transmitting
    {
      Wire.beginTransmission (WII_NUNCHUCK_TWI_ADR); // transmit to device 0x52
      Wire.send (0xFB); // sends memory address
      Wire.send (0x00); // sends sent a zero. 
      if(Wire.endTransmission () == 0) // stop transmitting
      {
        rc = 0;
      }
    }
  }
  while (rc != 0 && (!timeout || ((millis() - time) < timeout)));
  return rc;
}



void clearTwiInputBuffer(void)
{
  // clear the receive buffer from any partial data
  while( Wire.available ())
    Wire.receive ();
}


void send_zero ()
{
  // I don't know why, but it only works correct when doing this exactly 3 times
  // otherwise only each 3rd call reads data from the controller (cnt will be 0 the other times)
  for(byte i = 0; i < 3; i++)
  {
    Wire.beginTransmission (WII_NUNCHUCK_TWI_ADR); // transmit to device 0x52
    Wire.send (0x00); // sends one byte
    Wire.endTransmission (); // stop transmitting
    //delay(1);
  }
}

void loop (){
  delay (100);
  send_zero (); // send the request for next bytes
  Wire.requestFrom (WII_NUNCHUCK_TWI_ADR, WII_TELEGRAM_LEN); // request data from nunchuck

  for (cnt = 0; (cnt < WII_TELEGRAM_LEN) && Wire.available (); cnt++)
  {
    outbuf[cnt] = Wire.receive (); // receive byte as an integer
  }

  // debugging

  clearTwiInputBuffer();

  // If we received the 6 bytes, then use them ...
  if (cnt >= WII_TELEGRAM_LEN){
    button_state = bitRead(outbuf[5], 0); // Read input value
    if (button_state == 0) {              // Check if Z-button is  pressed
      // Yes, input is 0
      // If LED is on, turn it off
      // If LED is off, turn it on
      if ((led_state == 0) && (change == 0)){
        digitalWrite(13, HIGH);           // turn LED ON, accel control
        led_state = 1;
        change = 1;                       // Set change, prevent new change
      }
      if ((led_state == 1) && (change == 0)){ 
        digitalWrite(13, LOW);            // turn LED OFF, joystick control
        led_state = 0;
        change = 1;                       // Set change, prevent new change
      }
    }
    else {                                // Z-button released,
      change = 0;                         // input is HIGH again, reset change,
    }                                     // allow new change

    if(led_state == 0){                   // Joystick control
      byte joy_x = outbuf[0];
      byte joy_y = outbuf[1];

      int xval = joy_x - joy_x_mid;
      int yval = joy_y - joy_y_mid;

      if(yval >= 0){
        leftForw(constrain(yval + xval, 0, 255));
        rightForw(constrain(yval - xval, 0, 255));
      }
      if(yval < 0){
        leftBackw(constrain(-yval + xval, 0, 255));
        rightBackw(constrain(-yval - xval, 0, 255));
      }
    }
  }
  if(led_state == 1){                     // Accelerometer control
    unsigned int accel_x_axis = outbuf[2] << 2; 
    unsigned int accel_y_axis = outbuf[3] << 2;

    if (bitRead(outbuf[5], 2) == 1){ 
      bitSet(accel_x_axis, 1);
    }
    if (bitRead(outbuf[5], 3) == 1){
      bitSet(accel_x_axis, 0);
    }
    if (bitRead(outbuf[5], 4) == 1){
      bitSet(accel_y_axis, 1);
    }
    if (bitRead(outbuf[5], 5) == 1){
      bitSet(accel_y_axis, 0);
    }
    int xval = accel_x_axis - acc_x_mid;
    int yval = accel_y_axis - acc_y_mid;

    if(yval >= 0){
      leftForw(constrain(yval + xval, 0, 255));
      rightForw(constrain(yval - xval, 0, 255));
    }
    if(yval < 0){
      leftBackw(constrain(-yval + xval, 0, 255));
      rightBackw(constrain(-yval - xval, 0, 255));
    }
  }
}

void rightForw(byte speed){              // Motor code blocks
  digitalWrite(right1, LOW);
  analogWrite(right2, speed);
}
void rightBackw(byte speed){
  analogWrite(right1, speed);
  digitalWrite(right2, LOW);
}

void leftForw(byte speed){
  analogWrite(left1, speed);
  digitalWrite(left2, LOW);
}
void leftBackw(byte speed){
  digitalWrite(left1, LOW);
  analogWrite(left2, speed); 
}