Blog 19

From BitWizard Wiki
Jump to navigation Jump to search

2 Wheeled car: Arduino Version

#define Motor 0x48

#include <Wire.h> 

//Time to pause rotating
//static unsigned long Pause = 10000;
static unsigned long Speed = 40;

void setup()
{
  Wire.begin(); // wake up I2C bus
  Serial.begin(9600);
}

byte get_var(byte address, byte reg)
{
  byte value;   
  Wire.beginTransmission(address);  
  Wire.write(reg);
  Wire.endTransmission(); 
  delayMicroseconds (10);
  Wire.requestFrom(Motor, 1);
  value = Wire.read();
  return value;
} 

void set_var(byte address, byte reg, byte value)
{
  Wire.beginTransmission(address); // transmit to motor     
  delayMicroseconds  (10);
  Wire.write(reg);
  delayMicroseconds  (10);
  Wire.write(value);   
  Wire.endTransmission();    // stop transmitting
} 

void loop()
{
  unsigned long AddressA;
  unsigned long AddressB;  

  char buf[32];
  set_var(0x48, 0x21, Speed); 
  set_var(0x48, 0x31, Speed);  

  AddressA = get_var(0x48, 0x21);
  sprintf (buf, "Speed:  A:%d ", AddressA);
  Serial.write (buf); 

  AddressB = get_var(0x48, 0x31);
  sprintf (buf, " B:  %d\r\n", AddressB);
  Serial.write (buf); 
 
 delay(500);

//  delay(Pause);
}

This is the list I have made for the Raspberry Pi Version, what also counts for the Arduino version(If your car is switched to the other side this can of course be the opposite):

  • # X is forwards - Y is backwards
  • #Wheels at front
  • #20 A backwards
  • #21 A forwards
  • #22 A stop
  • #30 B backwards
  • #31 B forwards
  • #32 B stop

You can also check the motor protocol, for more info.

In my example script we go forward with 0x21 + 0x31 having the same value. For other movements you should have(If you car is flipped this can of course be the opposite!):

To go backwards:

  set_var(0x48, 0x20, Same Speed value); 
  set_var(0x48, 0x30, Same Speed value); 

To go left:

  set_var(0x48, 0x21, High Speed value); 
  set_var(0x48, 0x31, Low Speed value); 

To go right:

  set_var(0x48, 0x21, Low Speed value); 
  set_var(0x48, 0x31, High Speed value); 

To stop the car:

  set_var(0x48, 0x22, Speed value doesn't matter); 
  set_var(0x48, 0x32, Speed value doesn't matter);

To rotate to the left:

  set_var(0x48, 0x21, Same Speed value); 
  set_var(0x48, 0x30, Same Speed value); 

To rotate to the right:

  set_var(0x48, 0x20, Same Speed value); 
  set_var(0x48, 0x31, Same Speed value);

If you do this don't forget to add: static unsigned long Speed2 = "Put here your value";

How to change the SPI address, when the same addresses are connected on 1 port (Raspberry Pi)

( At the bottom of Blog 03 you can read how to change the address of an I2C Device )

Here I want to tell you quickly how to make it possible to connect an 7Fets attached to an other 7Fets connected to a raspberry Pi. When you connect a device on SPI0 and and you scan:

bw_tool -S -D /dev/spidev0.0

You will see:

88: spi_7fets 1.1

This is something you don't want, because now he only sees 1 7FETs. And with the car you of course want to make it possible to let the car drive different directions. To do this you first have to remove the 7FETs you got connected to the other 7FETs that is connected to the port. Now you should change the address of the connected 7FETs. ( If you would have both of the 7FETs connected both the addresses will change to the new one ) To change the address you have to do the command:

bw_tool -S -D /dev/spidev0.0 -a 88 -w f1:55 f2:aa f0:70

( If you are using I2C, that works the same only you have to change -S to -I and /dev/spidev0.0 to /dev/spi-i2c-1 )

What the code does:

f1:55

opens the address

f2:aa 

allows changing the address

f0:70

Is me changing the address to 70. ( You can of course give your own value )

On User Interface you can read more about the commands.

If you then connect the other 7FETs on the other 7FETs again and scan again you will get as result: 70: spi_7fets 1.1 88: spi_7fets 1.1

You can now easily talk to both 7FETs.

I2C Scanner: Arduino

Here is a link to the I2C scanner code from Arduino playground:

You don't need to change anything to the code. When you run the code and you have for example the Motor attached you will get this as result in the serial monitor.

I2C SCANNER
Scanning...
I2C device found at address 0x48  !
done

You maybe be asking why it is 0x48, while you can see it in the default addresses as 0x90. That is because on I2C it is getting divided by 2. So: 0x90/2=0x48. If you are getting confused it is 0x48 and not 0x45, because it is in hexadecimals.

I will also give link you to the arduino playground, if you want more information.

2 Wheeled 7FETs Car: Arduino Version

In this script I will show how to let 2 7FETs that are connected with a stepper motor drive forward. If you scroll down you will also see how to go left, right and backwards.

const int SPICLK  = 13;
const int SPIMOSI = 11;
const int SPIMISO = 12;
const int SPISS  = 10;

#define WAIT1 50
#define WAIT2 30

void SPIinit(void)
{
  pinMode (SPICLK,  OUTPUT);
  pinMode (SPIMOSI, OUTPUT);
  pinMode (SPIMISO, OUTPUT);
  pinMode (SPISS,   OUTPUT);
  digitalWrite (SPISS, 1);
  
  SPCR    =  _BV(SPE) | _BV(MSTR) | _BV(SPR1) | _BV(SPR0);
}

unsigned char SPI(char d) 
{  // send character over SPI
  char received = 0;
  SPDR = d;
  while(!(SPSR & _BV(SPIF)));
  received = SPDR;
  return (received);
}  

void SPI_startpkt (void)
{
  digitalWrite (SPISS, 0);
} 

void SPI_endpkt (void)
{
  digitalWrite (SPISS, 1);
}

void set_var (unsigned char addr, unsigned char a, unsigned char v)
{
  SPI_startpkt ();
  delayMicroseconds (WAIT1);
  SPI (addr);
  delayMicroseconds (WAIT2);
  SPI (a);
  delayMicroseconds (WAIT2);
  SPI (v);
  delayMicroseconds (WAIT2);
  SPI_endpkt ();   
}

void set_var32 (unsigned char addr, unsigned char a, unsigned long v)
{
  SPI_startpkt ();
  delayMicroseconds (WAIT1);
  SPI (addr);
  delayMicroseconds (WAIT2);
  SPI (a);
  delayMicroseconds (WAIT2);
  SPI (v);
  delayMicroseconds (WAIT2);
  SPI (v>>8);
  delayMicroseconds (WAIT2);
  SPI (v>>16);
  delayMicroseconds (WAIT2);
  SPI (v>>24);
  delayMicroseconds (WAIT2);
  SPI_endpkt ();   
}
 
unsigned long get_var32 (unsigned char addr, unsigned char a)
{
  unsigned long v;
  
  SPI_startpkt ();
  delayMicroseconds (WAIT1);
  SPI (addr+1);
  delayMicroseconds (WAIT2);
  SPI (a);
  delayMicroseconds (WAIT2);
  v = (unsigned long)SPI (0x00);
  delayMicroseconds (WAIT2);
  v |= (unsigned long)SPI (0x00) << 8;
  delayMicroseconds (WAIT2);
  v |= (unsigned long)SPI (0x00) << 16;
  delayMicroseconds (WAIT2);
  v |= (unsigned long) SPI (0x00) << 24;
  delayMicroseconds (WAIT2);
  SPI_endpkt ();    
  return v;
} 

// The given addresses to talk to.
static unsigned char spi_7fet_Raddr = 0x88;
static unsigned char spi_7fet_Laddr = 0x70;

//Time to pause rotating
static unsigned long Pause = 10000;
//Amount you want the stepper motor to rotate (0x200 = 25%  0x400 = 50% 0x800= 100% ) RotL means rotation of the left wheel.  
static unsigned long Rot = 0x200;
static unsigned long RotL = 0x200;

void setup() {
  //declare the motor pins as outputs
  SPIinit ();  
  Serial.begin(9600);
  char buf[32];
  unsigned long RTar;
  unsigned long RCur; 
  unsigned long LTar;
  unsigned long LCur; 

  //Makes the current(0x40) + current(0x41) zero of both addresses. Handy if the current + target have a too big difference. 
  set_var32(0x88, 0x40, 0x00);
  set_var32(0x88, 0x41, 0x00);
  set_var32(0x70, 0x40, 0x00);
  set_var32(0x70, 0x41, 0x00);

  //Change the step delay //50 is 4 times as fast as he normally goes (200)
  set_var(0x88, 0x43, 200);
  set_var(0x70, 0x43, 200);

  //Read current and read target from both the addresses
  RTar = get_var32 (0x88, 0x41);
  sprintf (buf, "RIGHT FTarget: %08lx\r\n", RTar );
  Serial.write (buf);

  RCur = get_var32 (0x88, 0x40);
  sprintf (buf, "RIGHT Fcur:    %08lx\r\n", RCur);
  Serial.write (buf);

  LTar = get_var32 (0x70, 0x41);
  sprintf (buf, "LEFT FTarget: %08lx\r\n", LTar );
  Serial.write (buf);

  LCur = get_var32 (0x70, 0x40);
  sprintf (buf, "LEFT Fcur:    %08lx\r\n", LCur);
  Serial.write (buf);

}

void loop()
{
  unsigned long RF;
  unsigned long RCur;
  unsigned long LCur;
  unsigned long LF;

  char buf[32];
  //sets rotation values of Rot & RotL
  set_var32(0x88, 0x42, Rot); 
  set_var32(0x70, 0x42, RotL); 
 
  //Reads target of both the addresses
  RF = get_var32 (0x88, 0x41);
  sprintf (buf, " RTarget:  %08lx", RF);
  Serial.write (buf);

  LF = get_var32 (0x70, 0x41);
  sprintf (buf, " LTarget:  %08lx\r\n", LF);
  Serial.write (buf);

  do {
    delay(200);
    
    //Reads current of both addresses
    RCur = get_var32 (0x88, 0x40);
    sprintf (buf, " Rcur:     %08lx", RCur);
    Serial.write (buf);

    LCur = get_var32 (0x70, 0x40);
    sprintf (buf, " Lcur:     %08lx\r\n", LCur);
    Serial.write (buf);

    // looks if current is the same as the target from address 88 RF( Right forward wheel )
  } while (RCur != RF);

  delay(Pause);  
}

All the information, of the code if have put after the two slashes(//). If you need some more information, you can check: Blog 15, where I worked out working with one stepper motor.

Other movements:

Go backwards(You have to add a minus before the rotation value.(You can also add the minus in the loop before rot)): outside void setup & loop:

static unsigned long Rot = -0x400;
static unsigned long Rot2 = -0x400;

in void setup:

 set_var(0x88, 0x43, 200);
 set_var(0x70, 0x43, 200);

Going left: outside void setup & loop:

static unsigned long Rot = 0x400;
static unsigned long Rot2 = 0x200;

in void setup:

 set_var(0x88, 0x43, 100);
 set_var(0x70, 0x43, 200);

Going Right: outside void setup & loop:

static unsigned long Rot = 0x200;
static unsigned long Rot2 = 0x400;

in void setup:

 set_var(0x88, 0x43, 200);
 set_var(0x70, 0x43, 100);

Useful links

  • Blog 03, at the bottom it shows how to see and to change the I2C address