Revision: 8010
http://playerstage.svn.sourceforge.net/playerstage/?rev=8010&view=rev
Author: gbiggs
Date: 2009-07-13 23:37:43 +0000 (Mon, 13 Jul 2009)
Log Message:
-----------
Applied patch #2820998
Modified Paths:
--------------
code/player/trunk/server/drivers/position/motionmind/motionmind.cc
Modified: code/player/trunk/server/drivers/position/motionmind/motionmind.cc
===================================================================
--- code/player/trunk/server/drivers/position/motionmind/motionmind.cc
2009-07-13 23:34:19 UTC (rev 8009)
+++ code/player/trunk/server/drivers/position/motionmind/motionmind.cc
2009-07-13 23:37:43 UTC (rev 8010)
@@ -63,6 +63,13 @@
- address (int)
- Default 1
- Address of the motionmind board that you wish to control
+- cpr (int)
+ - Default 500
+ - counts per motor rotation
+- gear_ratio
+ - Default 1.0
+ - n:1 gear_ratio - robot position in m or rad:motor rotation
+ - divide the gear_ratio by 2*PI for rotational actuators
@par Example
@@ -81,6 +88,8 @@
provides ["position1d:1"]
requires ["opaque:0"]
address 2
+ cpr 500
+ gear_ratio 2.0
)
driver(
@@ -112,8 +121,35 @@
#define DEFAULT_RX_BUFFER_SIZE 128
#define DEFAULT_ADDRESS 1
#define MESSAGE_LENGTH 7
-#define MSG_TIMEOUT 0.25 //Seconds before it sends another read request if it
hasn't yet got a reply
+#define MM_WRITE_MESSAGE_LENGTH 8
+#define MM_MSG_WAIT 20000 //microseconds to wait before sending another
command
+ // s/b 1250 according documentation but had comm
errors below 20000
+#define MSG_TIMEOUT 250000 //microseconds before it sends another read request
if it hasn't yet got a reply
+#define MM_DATA_WAIT 2500 //microseconds to wait before checking for response
data
+#define MM_CPU_WAIT 10000 //microseconds to wait before checking for missing
response data and to prevent CPU overloading
+#define MM_DEFAULT_CPR 500
+#define MM_DEFAULT_GEAR_RATIO 1.0
+#define MM_READ_POSITION 0x01 // Data0
+#define MM_READ_STATUS 0x01 // Data2
+#define MM_WRITE_REG 0x18
+// Status register bit packing
+#define MM_STATUS_NEGLIMIT 0x0001
+#define MM_STATUS_POSLIMIT 0x0002
+#define MM_STATUS_BRAKE 0x0004
+#define MM_STATUS_INDEX 0x0008
+#define MM_STATUS_BADRC 0x0010
+#define MM_STATUS_VNLIMIT 0x0020
+#define MM_STATUS_VPLIMIT 0x0040
+#define MM_STATUS_CURRENTLIMIT 0x0080
+#define MM_STATUS_PWMLIMIT 0x0100
+#define MM_STATUS_INPOSITION 0x0200
+
+// Register indexes for WRITE and WRITE STORE commands
+#define MM_REG_POSITION 0x00
+
+extern PlayerTime *GlobalTime;
+
///////////////////////////////////////////////////////////////////////////////
// The class for the driver
class MotionMind : public ThreadedDriver
@@ -134,22 +170,37 @@
private:
- // Main function for device thread.
- virtual void Main();
+ // Main function for device thread.
+ virtual void Main();
- //Requests the pos of the robot if it hasnt been already, othwise
publishes where it is
+ //Requests the pos of the robot if it hasnt been already
void FindCurrentPos();
+ //Requests the status register of the robot if it hasn't been already
+ void FindCurrentStatus();
// Checks whether or not you have sent a request for the position
bool pos_request_sent;
- struct timeval time_sent;
+ bool status_request_sent;
+ struct timeval msg_sent;
+ struct timeval time_sent_pos;
+ struct timeval time_sent_status;
+ int MsgWait();
//Makes a command to be sent to the opaque driver
void makeAbsolutePositionCommand(uint8_t* buffer, unsigned int address,
float position);
//Makes a command which requests the current osition bback from the
motor ocntroller
void makeReadPositionCommand(uint8_t* buffer, unsigned int address);
+ //Makes a command which requests the current status back from the motor
controller
+ void makeReadStatusCommand(uint8_t* buffer, unsigned int address);
+
+ //Makes a command which sets the odometry to the given value
+ void makeSetOdomReq(uint8_t* buffer, unsigned int address, const float
position);
+
+ //Converts robot positions to absolute motionmind positions
+ int robot2abspos(const float position);
+
// The function to do stuff here
void DoStuff();
@@ -165,6 +216,14 @@
unsigned int rx_buffer_size;
unsigned int rx_count;
+ // player position1 data odometric pose, velocity and motor stall info
+ player_position1d_data_t pos_data;
+
+ // counts per rotation
+ int cpr;
+
+ // gear ratio robot:motor
+ double gear_ratio;
};
@@ -217,8 +276,15 @@
rx_buffer = new uint8_t[rx_buffer_size];
assert(rx_buffer);
- pos_request_sent = false;
+ cpr = cf->ReadInt(section, "cpr", MM_DEFAULT_CPR);
+ this->gear_ratio = cf->ReadFloat(section, "gear_ratio",
MM_DEFAULT_GEAR_RATIO);
+ if (this->gear_ratio == 0.0) fprintf (stderr,"gear_ratio cannot be 0.0:
adjust your gear_ratio value");
+ assert(this->gear_ratio != 0.0);
+
+ this->pos_request_sent = false;
+ this->status_request_sent = false;
+ GlobalTime->GetTime(&(this->msg_sent));
return;
}
@@ -306,10 +372,30 @@
player_opaque_data_t mData;
mData.data_count = MESSAGE_LENGTH;
mData.data = buffer;
+ this->MsgWait();
opaque->PutMsg(this->InQueue, PLAYER_MSGTYPE_CMD,
PLAYER_OPAQUE_CMD_DATA, reinterpret_cast<void*>(&mData),0,NULL);
+ GlobalTime->GetTime(&(this->msg_sent));
delete [] buffer;
return(0);
}
+ if(Message::MatchMessage(hdr, PLAYER_MSGTYPE_REQ,
+
PLAYER_POSITION1D_REQ_SET_ODOM,
+ this->device_addr))
+ {
+ assert(hdr->size == sizeof(player_position1d_set_odom_req_t));
+ player_position1d_set_odom_req_t* req =
reinterpret_cast<player_position1d_set_odom_req_t*> (data);
+ uint8_t* buffer = new uint8_t[MM_WRITE_MESSAGE_LENGTH];
+ this->makeSetOdomReq(buffer, this->address, req->pos);
+ player_opaque_data_t mData;
+ mData.data_count = MM_WRITE_MESSAGE_LENGTH;
+ mData.data = buffer;
+ this->MsgWait();
+ opaque->PutMsg(this->InQueue, PLAYER_MSGTYPE_CMD,
PLAYER_OPAQUE_CMD_DATA, reinterpret_cast<void*>(&mData),0,NULL);
+ GlobalTime->GetTime(&(this->msg_sent));
+ delete [] buffer;
+ return(0);
+ }
+
return -1;
}
@@ -327,11 +413,14 @@
// Process incoming messages
ProcessMessages();
- // Ask for the current position and publish it
+ // Ask for the current position
FindCurrentPos();
+ // Ask for the current position status
+ FindCurrentStatus();
+ // Publish position data
+ this->Publish(this->device_addr, PLAYER_MSGTYPE_DATA,
PLAYER_POSITION1D_DATA_STATE, (void*)&pos_data);
- //usleep is called in FindCurrentPos to prevent overloading
- //usleep(10000);
+ usleep(MM_CPU_WAIT);
}
return;
}
@@ -340,7 +429,7 @@
void MotionMind::makeAbsolutePositionCommand(uint8_t* buffer, unsigned int
address, float position)
{
unsigned int checksum = 0;
- int posInt = static_cast<int> (position);
+ int posInt = robot2abspos(position);
char* pos = (char*)&posInt;
buffer[0] = 0x15;
checksum += buffer[0];
@@ -355,31 +444,101 @@
buffer[5] = pos[3];
checksum += buffer[5];
buffer[6] = checksum;
- buffer[7] = 0x00;
}
void MotionMind::makeReadPositionCommand(uint8_t* buffer, unsigned int address)
{
unsigned int checksum = 0;
+ // Command
buffer[0] = 0x1A;
checksum += buffer[0];
+ // Address
buffer[1] = address;
checksum += buffer[1];
- buffer[2] = 0x01;
+ // Data0
+ buffer[2] = MM_READ_POSITION;
checksum += buffer[2];
+ // Data1
buffer[3] = 0x00;
checksum += buffer[3];
+ // Data2
buffer[4] = 0x00;
checksum += buffer[4];
+ // Data3
buffer[5] = 0x00;
checksum += buffer[5];
+ //Checksum
buffer[6] = checksum;
- buffer[7] = 0x00;
}
+void MotionMind::makeReadStatusCommand(uint8_t* buffer, unsigned int address)
+{
+ unsigned int checksum = 0;
+ // Command
+ buffer[0] = 0x1A;
+ checksum += buffer[0];
+ // Address
+ buffer[1] = address;
+ checksum += buffer[1];
+ // Data0
+ buffer[2] = 0x00;
+ checksum += buffer[2];
+ // Data1
+ buffer[3] = 0x00;
+ checksum += buffer[3];
+ // Data2
+ buffer[4] = MM_READ_STATUS;
+ checksum += buffer[4];
+ // Data3
+ buffer[5] = 0x00;
+ checksum += buffer[5];
+ //Checksum
+ buffer[6] = checksum;
+}
+
+void MotionMind::makeSetOdomReq(uint8_t* buffer, unsigned int address, float
position)
+{
+ unsigned int checksum = 0;
+ uint32_t posInt = robot2abspos(position);
+ printf("Setting position register to %0.6f : %d\n",position,posInt);
+ char* pos = (char*)&posInt;
+ // Command
+ buffer[0] = MM_WRITE_REG;
+ checksum += buffer[0];
+ // Address
+ buffer[1] = address;
+ checksum += buffer[1];
+ // Index
+ buffer[2] = MM_REG_POSITION;
+ checksum += buffer[2];
+ // Data0
+ buffer[3] = pos[0];
+ checksum += buffer[3];
+ // Data1
+ buffer[4] = pos[1];
+ checksum += buffer[4];
+ // Data2
+ buffer[5] = pos[2];
+ checksum += buffer[5];
+ // Data3
+ buffer[6] = pos[3];
+ checksum += buffer[6];
+ //Checksum
+ buffer[7] = checksum;
+}
+
+int MotionMind::robot2abspos(const float position)
+{
+ assert(this->gear_ratio != 0.0);
+ int abspos = static_cast<int>
((double)position*(double)this->cpr*this->gear_ratio);
+ return abspos;
+}
+
// Currently this alternates between reading the pedal position and reading
the steering position
void MotionMind::FindCurrentPos()
{
+ long elapsed;
+ struct timeval curr;
if (!this->pos_request_sent)
{
uint8_t * buffer = new uint8_t[MESSAGE_LENGTH];
@@ -387,20 +546,24 @@
player_opaque_data_t mData;
mData.data_count = MESSAGE_LENGTH;
mData.data = buffer;
+ this->MsgWait();
opaque->PutMsg(this->InQueue, PLAYER_MSGTYPE_CMD,
PLAYER_OPAQUE_CMD_DATA, reinterpret_cast<void*>(&mData),0,NULL);
+ GlobalTime->GetTime(&(this->msg_sent));
delete [] buffer;
this->pos_request_sent = true;
- GlobalTime->GetTime(&(this->time_sent));
- usleep(10000);
+ GlobalTime->GetTime(&(this->time_sent_pos));
+ usleep(MM_DATA_WAIT);
}
- else
+ while (this->pos_request_sent)
{
- struct timeval curr;
+ ProcessMessages();
GlobalTime->GetTime(&curr);
- if ((curr.tv_sec - this->time_sent.tv_sec)*1e6 + (curr.tv_usec
- this->time_sent.tv_usec) > MSG_TIMEOUT*1e6)
+ elapsed = (curr.tv_sec - this->time_sent_pos.tv_sec)*1e6 +
(curr.tv_usec - this->time_sent_pos.tv_usec);
+ if ((curr.tv_sec - this->time_sent_pos.tv_sec)*1e6 +
(curr.tv_usec - this->time_sent_pos.tv_usec) > MSG_TIMEOUT)
{
- PLAYER_WARN("mm message timeout triggered");
+ printf("%d %ld mm pos request message timeout
triggered\n",opaque_id.index,elapsed);
this->pos_request_sent = false;
+ break;
}
// Ensures that you are reading from the right point in the
stream
while( (rx_count > 0) && (rx_buffer[0] != this->address))
@@ -433,23 +596,116 @@
}
else
{
- player_position1d_data_t data_packet;
- data_packet.pos = static_cast<float> (position);
- this->Publish(this->device_addr,
PLAYER_MSGTYPE_DATA, PLAYER_POSITION1D_DATA_STATE, (void*)&data_packet);
+ GlobalTime->GetTime(&curr);
+ float robot_pos =
(float)((double)position/(this->gear_ratio*((double)cpr)));
+ this->pos_data.pos = robot_pos;
rx_count -= 6;
memmove(rx_buffer+6, rx_buffer, rx_count);
- pos_request_sent = false;
+ this->pos_request_sent = false;
}
}
else
{
// Prevents the CPU from becoming overloaded
- usleep(10000);
+ usleep(MM_CPU_WAIT);
}
}
+ GlobalTime->GetTime(&curr);
+ elapsed = (curr.tv_sec - this->time_sent_pos.tv_sec)*1e6 +
(curr.tv_usec - this->time_sent_pos.tv_usec);
}
+void MotionMind::FindCurrentStatus()
+{
+ long elapsed;
+ struct timeval curr;
+ if (!this->status_request_sent)
+ {
+ // printf("%d MotionMind FindCurrentStatus sending status
request\n",opaque_id.index);
+ uint8_t * buffer = new uint8_t[MESSAGE_LENGTH];
+ makeReadStatusCommand(buffer, this->address);
+ player_opaque_data_t mData;
+ mData.data_count = MESSAGE_LENGTH;
+ mData.data = buffer;
+ this->MsgWait();
+ opaque->PutMsg(this->InQueue, PLAYER_MSGTYPE_CMD,
PLAYER_OPAQUE_CMD_DATA, reinterpret_cast<void*>(&mData),0,NULL);
+ GlobalTime->GetTime(&(this->msg_sent));
+ delete [] buffer;
+ this->status_request_sent = true;
+ GlobalTime->GetTime(&(this->time_sent_status));
+ usleep(MM_DATA_WAIT);
+ }
+ while (this->status_request_sent)
+ {
+ ProcessMessages();
+ GlobalTime->GetTime(&curr);
+ elapsed = (curr.tv_sec - this->time_sent_status.tv_sec)*1e6 +
(curr.tv_usec - this->time_sent_status.tv_usec);
+ if ((curr.tv_sec - this->time_sent_status.tv_sec)*1e6 +
(curr.tv_usec - this->time_sent_status.tv_usec) > MSG_TIMEOUT)
+ {
+ printf("%d %ld mm status message request timeout
triggered\n",opaque_id.index,elapsed);
+ this->status_request_sent = false;
+ break;
+ }
+ // Ensures that you are reading from the right point in the
stream
+ while( (rx_count > 0) && (rx_buffer[0] != this->address))
+ {
+ memmove(rx_buffer, rx_buffer+1, rx_count - 1);
+ rx_count--;
+ }
+ if (rx_count >= 4)
+ {
+ assert (rx_buffer[0] == this->address);
+ int32_t status = 0;
+ unsigned char* stat = (unsigned char*)&status;
+ unsigned int checksum = rx_buffer[0];
+ unsigned char* csum = (unsigned char*)&checksum;
+ stat[0] = rx_buffer[1];
+ checksum += rx_buffer[1];
+ stat[1] = rx_buffer[2];
+ checksum += rx_buffer[2];
+ if (csum[0] != rx_buffer[3])
+ {
+ // Checksums don't match - not necessarily bad
as it can be due to the address header being in the middle of a responce
+ // to another driver with a different address
e.g. the responce is 02 01 xx xx xx xx, the data being sent to device 2
+ // with the info 01 xx xx xx.
+ memmove(rx_buffer, rx_buffer+1, rx_count - 1);
+ rx_count--;
+ }
+ else
+ {
+ this->pos_data.status =
+ (status & MM_STATUS_NEGLIMIT ? 0x01 :
0x00) // NEGLIMIT -> lim min
+ | (status & MM_STATUS_POSLIMIT ? 0x04 :
0x00) // POSLIMIT -> lim max
+ | (status & MM_STATUS_CURRENTLIMIT ?
0x08 : 0x00) // CURRENTLIMIT -> over current
+ | (status & MM_STATUS_INPOSITION ? 0x10
: 0x00) // INPOSITION -> trajectory complete
+ | (status & MM_STATUS_BRAKE ? 0x00 :
0x20); // BRAKE -> is enabled (inverted)
+ rx_count -= 4;
+ memmove(rx_buffer+4, rx_buffer, rx_count);
+ status_request_sent = false;
+ }
+ }
+ else
+ {
+ // Prevents the CPU from becoming overloaded
+ usleep(MM_CPU_WAIT);
+ }
+ }
+ elapsed = (curr.tv_sec - this->time_sent_status.tv_sec)*1e6 +
(curr.tv_usec - this->time_sent_status.tv_usec);
+}
+int MotionMind::MsgWait()
+{
+ struct timeval curr;
+ long elapsed;
+ GlobalTime->GetTime(&curr);
+ elapsed = (curr.tv_sec - this->msg_sent.tv_sec)*1e6 + (curr.tv_usec -
this->msg_sent.tv_usec);
+ while (elapsed < MM_MSG_WAIT)
+ {
+ usleep(MM_MSG_WAIT-elapsed);
+ GlobalTime->GetTime(&curr);
+ elapsed = (curr.tv_sec - this->msg_sent.tv_sec)*1e6 +
(curr.tv_usec - this->msg_sent.tv_usec);
+ }
+ return 0;
+}
This was sent by the SourceForge.net collaborative development platform, the
world's largest Open Source development site.
------------------------------------------------------------------------------
Enter the BlackBerry Developer Challenge
This is your chance to win up to $100,000 in prizes! For a limited time,
vendors submitting new applications to BlackBerry App World(TM) will have
the opportunity to enter the BlackBerry Developer Challenge. See full prize
details at: http://p.sf.net/sfu/Challenge
_______________________________________________
Playerstage-commit mailing list
[email protected]
https://lists.sourceforge.net/lists/listinfo/playerstage-commit