OpenServo.com Forum Index OpenServo.com
Discussion of the OpenServo project
 
 FAQFAQ   SearchSearch   MemberlistMemberlist   UsergroupsUsergroups   RegisterRegister 
 ProfileProfile   Log in to check your private messagesLog in to check your private messages   Log inLog in 

Basic Arduino/Openservo/I2C Interfacing Question
Goto page 1, 2, 3  Next
 
Post new topic   Reply to topic    OpenServo.com Forum Index -> Software
View previous topic :: View next topic  
Author Message
quantumechanic



Joined: 04 Aug 2011
Posts: 4

PostPosted: Thu Aug 04, 2011 8:56 pm    Post subject: Basic Arduino/Openservo/I2C Interfacing Question Reply with quote

Greetings all,

I am trying to interface an Arduino Duemilanove (ATMega328) with an Openservo board purchased from Sparkfun. I am fairly confident that I have the hardware set up correctly and am having difficulty with the software implementation. From trolling the internets I am aware that the PID gains must be set on the Openservo before it can be made to move. I am trying to set the gains but my code does not seem to be working, here's what I have:

#include <Wire.h>

// OpenServo registers & commands
#define OPENSERVO_POSITION (0x08)
#define OPENSERVO_SEEK (0x10)
#define OPENSERVO_PWM_ENABLE (0x82)
#define OPENSERVO_PWM_DISABLE (0x83)
#define OPENSERVO_PID_WRITE_ENABLE (0x84)
#define OPENSERVO_PID_WRITE_DISABLE (0x85)
#define PID_PGAIN_HI (0x22)
#define PID_PGAIN_LO (0x23)
#define PID_DGAIN_HI (0x24)
#define PID_DGAIN_LO (0x25)
#define PID_IGAIN_HI (0x26)
#define PID_IGAIN_LO (0x27)
#define REGISTERS_SAVE (0x86)

// servo i2c addresses
#define SERVO_ADDRESS (0x7F)

void setup(){
Serial.begin(9600);
Wire.begin();

Wire.beginTransmission(SERVO_ADDRESS);
Wire.send(OPENSERVO_PID_WRITE_ENABLE); //this allows for PID gains to be set
Wire.send(0x01);
Wire.send(0x00);
Wire.endTransmission();

Wire.beginTransmission(SERVO_ADDRESS);
Wire.send(PID_PGAIN_HI);
Wire.send(0x05); //high byte
Wire.send(0x00);
Wire.endTransmission();
Wire.beginTransmission(SERVO_ADDRESS);
Wire.send(PID_PGAIN_LO);
Wire.send(0x04); //low byte
Wire.send(0x00);
Wire.endTransmission();

Wire.beginTransmission(SERVO_ADDRESS);
Wire.send(OPENSERVO_PID_WRITE_DISABLE);
Wire.send(0x00);
Wire.endTransmission();

Wire.beginTransmission(SERVO_ADDRESS);
Wire.send(REGISTERS_SAVE);
Wire.send(0x00);
Wire.endTransmission();
}

void loop(){
unsigned int value = _openservo_read16(SERVO_ADDRESS, PID_PGAIN_HI);
Serial.println(value, HEX);
}

My method is this:

1) Join I2C bus with Wire.begin()
2) Enable writing of PID gains by enabling PID ENABLE REGISTER
3) Set PID pgain HI and LO
4) Disable writing of PID gains
5) Save changes made with REGISTERS SAVE

Is this correct? I am a newbie at this.

Thanks in advance for any help.
Back to top
View user's profile Send private message
jharvey
co-admin


Joined: 15 Mar 2009
Posts: 350
Location: Maine USA

PostPosted: Fri Aug 05, 2011 10:23 am    Post subject: Reply with quote

How are you trying to connect to the OS? Are you using the OSIF from robot fuzz? Also how's the power supply? These need a really solid supply.
Back to top
View user's profile Send private message Visit poster's website
quantumechanic



Joined: 04 Aug 2011
Posts: 4

PostPosted: Fri Aug 05, 2011 5:36 pm    Post subject: Reply with quote

Thanks for the reply,

I am connecting to the OS via the Arduino board, I am not using the OSIF from robot fuzz. The power supply is a bench supply that can produce up to 25V. What is the exact code to set up the PID gains for the openservo.

Thanks
Back to top
View user's profile Send private message
jharvey
co-admin


Joined: 15 Mar 2009
Posts: 350
Location: Maine USA

PostPosted: Fri Aug 05, 2011 9:00 pm    Post subject: Reply with quote

I'm a bit ignorant about the exact I2C codes. I seem to recall there is a document on the web page that notes the commands.

The power supply should be beefy in current, not so much in voltage. I know the OSv3 was designed for a 7.2 v pack. I do a near equiv by setting my bench supply at 7.5v, and 5 amp current limit. I know it doesn't use 5 amps, but I set mine that high to get enough bulk for the short spikes.
Back to top
View user's profile Send private message Visit poster's website
petelewis



Joined: 26 Oct 2012
Posts: 14
Location: Boulder CO

PostPosted: Fri Oct 26, 2012 9:24 pm    Post subject: Any update on this? Reply with quote

Hey Quantumechanic,
I was having similar problems when I first started working with these (I couldn't get the motor to start moving). But then I found that my power supply wasn't allowing enough current. It seems to need at least 200mA during the spikes when the motor starts to turn.

But I am also facing another problem now. Although I can get the motor to turn, it doesn't seem to stop. I send it to seek a position (say 700) and it spins endlessly.

Have you been able to get your open servo to seek and hold a position successfully yet?

Thanks!
Back to top
View user's profile Send private message
jharvey
co-admin


Joined: 15 Mar 2009
Posts: 350
Location: Maine USA

PostPosted: Fri Oct 26, 2012 11:05 pm    Post subject: Reply with quote

Try flipping the motor wire leads. If the motor is backwards, the error will cause more error, rather than reduce error.
Back to top
View user's profile Send private message Visit poster's website
petelewis



Joined: 26 Oct 2012
Posts: 14
Location: Boulder CO

PostPosted: Thu Nov 01, 2012 8:39 pm    Post subject: Reply with quote

Hi Jharvey,
Thanks for your quick response. I tried swapping the motor wires and it seems to be trying to go to the correct position...

I've tried two test conditions:

(1) I put the servo at about position 500 (manually by hand), then turn it on and send the command to seek position 200. It turns in the correct direction, but overshoots it and then stops at 0.

(2) I put the servo at about position 500 (manually by hand), then turn it on and send the command to seek position 700. It turns in the correct direction, but overshoots it and then stops at 1023.

I have my PID_PGAIN_HI at 200, and my PID_DGAIN_HI at 240. And I am not setting the IGAIN.

Any other ideas to try?
Thanks!
Back to top
View user's profile Send private message
jharvey
co-admin


Joined: 15 Mar 2009
Posts: 350
Location: Maine USA

PostPosted: Thu Nov 01, 2012 10:42 pm    Post subject: Reply with quote

Can you get the software position out of it? Fore example, does it claim it's at 200 when you put it at position 200? I wonder if the POT is buggered some how. Does the POT range from near 0, to near 1024 when you move it by hand?

If you set P = 0, does it stop driving? Then again if you set P to say 1 Or something similar, does it drive weakly?

Also start with P only, and set PID_DGAIN_HI to 0. Also read that the other I and D terms are 0 to ensure there isn't some old values in those registers.

Also also, verify what you have written after you write to it, by reading the register. Such that you ensure it stuck. This verifies there wasn't some kind of communications issue.
Back to top
View user's profile Send private message Visit poster's website
petelewis



Joined: 26 Oct 2012
Posts: 14
Location: Boulder CO

PostPosted: Fri Nov 02, 2012 5:31 pm    Post subject: Reply with quote

Quote:
Can you get the software position out of it? Fore example, does it claim it's at 200 when you put it at position 200? I wonder if the POT is buggered some how. Does the POT range from near 0, to near 1024 when you move it by hand?

Yes, I am getting readings from 0-1023 when I manually move the pot. So I'm assuming this is working correctly.

Quote:
If you set P = 0, does it stop driving?

Yes.

Quote:
Then again if you set P to say 1 Or something similar, does it drive weakly?

No.

Quote:
Also start with P only, and set PID_DGAIN_HI to 0. Also read that the other I and D terms are 0 to ensure there isn't some old values in those registers.

Also also, verify what you have written after you write to it, by reading the register. Such that you ensure it stuck. This verifies there wasn't some kind of communications issue.


I think I may be having a communications issue. When I write all gains (P, D and I) to 0, they consistently read back at P = 0, D = 0, and I = 16.

What's strange is that when I write P to 200, the servo turns, (so I'm assuming that it is changing something), but it still reads back as P:0,D:0 and I:16.

Also, I can't seem to post all of my code - I don't think your forum is allowing me to post such a long post. Could you please look into this, I would like to share my code and readout.

Thanks!
Back to top
View user's profile Send private message
petelewis



Joined: 26 Oct 2012
Posts: 14
Location: Boulder CO

PostPosted: Fri Nov 02, 2012 5:32 pm    Post subject: Reply with quote

Here is my sketch:
#include <Wire.h>

// OpenServo registers & commands
#define OPENSERVO_POSITION 0x08
#define OPENSERVO_SEEK 0x10
#define OPENSERVO_PWM_ENABLE 0x82 //Enable PWM to motors
#define OPENSERVO_PWM_DISABLE 0x83
#define PID_DEADBAND 0x21
#define SWAP_PWM_DIRECTION_ENABLED 1 // as per d3smo comment on the product page https://www.sparkfun.com/products/9014?
#define WRITE_ENABLE 0x84 //Enable write of read/write protected registers
#define PID_PGAIN_HI 0x22
#define PID_DGAIN_HI 0x24
#define PID_IGAIN_HI 0x26
#define VELOCITY_HI 0x0A
#define SEEK_VELOCITY_HI 0x12
// servo i2c addresses
#define SERVO_ADDRESS 0x10

unsigned int value = 0;

/*
* OpenServo utility handlers
To move a servo to a position: Code: _openservo_write16(SERVO_ADDRESS, OPENSERVO_SEEK, value);
To get the current position: Code: unsigned int value = _openservo_read16(SERVO_ADDRESS, OPENSERVO_POSITION);
To disable PWM: Code: _openservo_command8(SERVO_ADDRESS, OPENSERVO_PWM_DISABLE);
*/

void setup(){
Wire.begin();
Serial.begin(9600);
Serial.println("hello");

_openservo_command8(SERVO_ADDRESS, WRITE_ENABLE);
_openservo_command8(SERVO_ADDRESS, OPENSERVO_PWM_ENABLE);


_openservo_write16(SERVO_ADDRESS, PID_PGAIN_HI, 0);
value = _openservo_read16(SERVO_ADDRESS, PID_PGAIN_HI);
Serial.print("P:");
Serial.println(value);

_openservo_write16(SERVO_ADDRESS, PID_DGAIN_HI, 0);
value = _openservo_read16(SERVO_ADDRESS, PID_DGAIN_HI);
Serial.print("D:");
Serial.println(value);

_openservo_write16(SERVO_ADDRESS, PID_IGAIN_HI, 0);
value = _openservo_read16(SERVO_ADDRESS, PID_IGAIN_HI);
Serial.print("I:");
Serial.println(value);

_openservo_write16(SERVO_ADDRESS, OPENSERVO_SEEK, 200);
delay(1000);
}

void loop(){
value = _openservo_read16(SERVO_ADDRESS, OPENSERVO_POSITION);
Serial.println(value);
delay(200);
}

void _openservo_write16(int i2c, byte reg, int data) {
// write a 16 bit register
_openservo_begin(i2c, reg);
Wire.write(data >> 8); // high byte
Wire.write(data & 0xff); // low byte
Wire.endTransmission();
}

unsigned int _openservo_read16(int i2c, byte reg) {
// read a 16 bit register
_openservo_begin(i2c, reg);
unsigned int data;
Wire.requestFrom(i2c, 2);
if (Wire.available()){
data = Wire.read() << 8; // high byte
}
if (Wire.available()) {
data |= Wire.read(); // low byte
}
Wire.endTransmission();
return data;
}

void _openservo_command8(int i2c, byte reg) {
// send an 8 bit command
_openservo_begin(i2c, reg);
Wire.endTransmission();
}

void _openservo_begin(int i2c, byte reg) {
// init an i2c transmission
Wire.beginTransmission(i2c);
Wire.write(reg);
}

And here is my readout (The changing values below are my manually changing the pot):

hello
P:0
D:0
I:16
0
352
352
352
352
352
352
254
41
0
0
0
0
45
149
216
314
404
478
563
694
872
1005
1023


Last edited by petelewis on Wed Nov 14, 2012 9:53 pm; edited 1 time in total
Back to top
View user's profile Send private message
jharvey
co-admin


Joined: 15 Mar 2009
Posts: 350
Location: Maine USA

PostPosted: Fri Nov 02, 2012 10:41 pm    Post subject: Reply with quote

Do you know for sure your read command is working correctly? Perhaps read the version #, or one of the read only parts. If you know read is correct, you can write 0's to all the write bytes, then read them all and and see if they stuck. If you find all but the first bits work correctly, it might show if your off by a byte or something. I'm ignorant about the Wire.write call. Perhaps it's off by 1, or perhaps the reg needs to be different than what you are sendind. Do you have a logic analyzer to sniff the I2C? Also I seem tor recall the registers changed from V2 to V3. I think you have V2, but don't know. So you might need to reference the firmware code to make sure you are reading and writing the correct codes. Have you tried the OSiF and it's affiliated software?
Back to top
View user's profile Send private message Visit poster's website
petelewis



Joined: 26 Oct 2012
Posts: 14
Location: Boulder CO

PostPosted: Mon Nov 05, 2012 6:39 pm    Post subject: Reply with quote

Quote:
Do you know for sure your read command is working correctly?

It seems like the read position is working properly, because it does read 0-1023 as I manually move the pot.

But I'm not sure if the read command is working for other registers.

Quote:
Perhaps read the version #


I tried reading the REG_VERSION_MAJOR (0x02) and REG_VERSION_MINOR (0x03), and I get funny responses:

Code:
   value = _openservo_read16(SERVO_ADDRESS, 0x02);
   Serial.println(value);
   delay(200);
   
   value = _openservo_read16(SERVO_ADDRESS, 0x02);
   Serial.println(value);
   delay(200);
   
   value = _openservo_read16(SERVO_ADDRESS, 0x03);
   Serial.println(value);
   delay(200);
   
   value = _openservo_read16(SERVO_ADDRESS, 0x03);
   Serial.println(value);
   delay(200);


And my serial responses are:

hello
512
2
2
512

I downloaded the most recent firmware from git here:
https://github.com/ginge/OpenServo/downloads

I recompiled it, and uploaded to my openservo board via ISP. It looks like I am reading the correct registers (when looking at the registers.h file).

I am working with a V2 board.

I will take a look at the I2C on a logic analyzer and report back, but do you have any idea what could be causing the strange readout above?

Thanks!
Back to top
View user's profile Send private message
petelewis



Joined: 26 Oct 2012
Posts: 14
Location: Boulder CO

PostPosted: Mon Nov 05, 2012 8:05 pm    Post subject: Will OSIF work with Bus Pirate? Reply with quote

Would the Bus Pirate work with the OSIF software to control my open servo?

https://www.sparkfun.com/products/9544

Or is it only possible with the interface offered at robotfuzz:

http://www.robotfuzz.com/index.php?main_page=product_info&cPath=66&products_id=181

Thanks!
Back to top
View user's profile Send private message
jharvey
co-admin


Joined: 15 Mar 2009
Posts: 350
Location: Maine USA

PostPosted: Mon Nov 05, 2012 11:30 pm    Post subject: Reply with quote

I've used the OSIF, seems to work OK. I seem to recall the driver was a bit of a bugger at times, but once I figured it out, it worked well. I have not used the bus pirate.
Back to top
View user's profile Send private message Visit poster's website
petelewis



Joined: 26 Oct 2012
Posts: 14
Location: Boulder CO

PostPosted: Tue Nov 13, 2012 10:12 pm    Post subject: Reply with quote

This is what I got for my first I2C communication. I'm not sure why it is coming up as "0x20" cause the servo address is "0x10" (and I've defined it that way). This makes me wonder how I have been able to read from the servo successfully (or communicate at all really). Is there a chance that my servo address has changed to 0x20?

However, the WRITE_ENABLE is coming up as 0x84, which is correct.

This is the code of my first communication:

_openservo_command8(SERVO_ADDRESS, WRITE_ENABLE);

And this is the data:

Back to top
View user's profile Send private message
Display posts from previous:   
Post new topic   Reply to topic    OpenServo.com Forum Index -> Software All times are GMT
Goto page 1, 2, 3  Next
Page 1 of 3

 
Jump to:  
You cannot post new topics in this forum
You cannot reply to topics in this forum
You cannot edit your posts in this forum
You cannot delete your posts in this forum
You cannot vote in polls in this forum


Powered by phpBB © 2001, 2005 phpBB Group