Go Down

Topic: Two's Complement (Read 494 times) previous topic - next topic

Chevelle

I am using an L6470 for a motion control project.  There is a library command (GoTo) that sends the motor to a specific location.  The value it accepts is the two's complement (unsigned long) of the absolute position. 

The routine I am writing that accepts a signed long from the user.  Positive values are absolute locations on one side of the home position ("0") and negative values are absolute positions on the other side of home.

I can send the position value directly to the GoTo function if the value is positive but I need to send the two's compliment of the negative values.  The values range from +/- 2,000,000.

I have been unable to convert the negative numbers into the unsigned two's complement.  I can get the binary expression the number but I need that value without the preservation of the sign bit.  The sign bit needs to represent the value at that bit location.

Any help is greatly appreciated.

AWOL

Two's complement - invert, and add one.

GolamMostafa

#2
Aug 10, 2019, 03:21 pm Last Edit: Aug 10, 2019, 03:23 pm by GolamMostafa
I have been unable to convert the negative numbers into the unsigned two's complement.  I can get the binary expression the number but I need that value without the preservation of the sign bit.  The sign bit needs to represent the value at that bit location.
1.  Assume your number is: -5.
2.  Forget the -ve sign; you get 5.
3.  Express the number of Step-2 in 8-bit binary; you get 00000101,
4.  Invert every bit of the number of Step-3; you get: 11111010.
5.  Add 1 with the number of Step-4; you get: 11111011 ==> 0xFB

The 2's complement form of -5 is 0xFB.

Codes:
Code: [Select]
char x = -5;    //x holds: 11111011
  for (int i = 7; i >= 0; i--)
  {
    Serial.print(bitRead(x, i), BIN);//shows: 11111011
  }

 

gfvalvo

#3
Aug 10, 2019, 03:31 pm Last Edit: Aug 10, 2019, 03:32 pm by gfvalvo
Would have been nice if you told is which library you're using. Is it one of these?
https://github.com/sparkfun/L6470-AutoDriver/tree/master/Libraries/Arduino
https://github.com/ameyer/Arduino-L6470/blob/master/src/L6470.h

In both of those, the GoTo() method take a 'long' (aka int32_t) as their argument. So, just send your signed value. It's in two-complement format by definition.
No technical questions via PM. They will be ignored. Post your questions in the forum so that all may learn.

Chevelle

In the code below, if valInt is -20,000

Code: [Select]

if (valInt < 0) { valInt =  ~valInt + B01; }
    
Serial.println(valInt, BIN);  // shows 1011000111100000
Serial.println(valInt); shows 20000 but should show 45536



The binary value is correct but when that is shown as its integer value, the msb remains the sign bit.  I am getting the feeling that I have to build the new integer value bitwise.

gfvalvo

You're over-thinking this.

First, if you won't tell us which library you're using, at least show us the signature of the GoTo() function.

If it doesn't match what you have, just cast it.
No technical questions via PM. They will be ignored. Post your questions in the forum so that all may learn.

AWOL

Quote
shows 20000 but should show 45536
It isn't possible to represent 45536 in a signed sixteen bit value.

Chevelle

Here is the link to the library I am using...

https://github.com/juttTechnology/L6470_Stepper_Driver_Api

The documentation says it requires an unsigned long.

AWOL

Would it be too obvious to point out that this is the programming section of the forum, but we can't see your code?

gfvalvo

OK, so the function prototype is:
Code: [Select]
void _GoTo(unsigned long);
and, it's name is actually _GoTo.

So, as I said, just take your signed variable and cast it to the required type:

Code: [Select]
objectName._GoTo((unsigned long) myVar);
No technical questions via PM. They will be ignored. Post your questions in the forum so that all may learn.

johnwasser

It looks like your assumption that you could use negative absolute positions is incorrect.  The code only allows for absolute positions between 0 and 0x3FFFFF (4,194,303).
Code: [Select]
// GOTO operates much like MOVE, except it produces absolute motion instead
//  of relative motion. The motor will be moved to the indicated position
//  in the shortest possible fashion.
void cL6470::_GoTo(unsigned long pos)
{

_Data_To_Transfer(x_GOTO);
if (pos > 0x3FFFFF) pos = 0x3FFFFF;
_Data_To_Transfer((byte)(pos >> 16));
_Data_To_Transfer((byte)(pos >> 8));
_Data_To_Transfer((byte)(pos));
}
Send Bitcoin tips to: 1G2qoGwMRXx8az71DVP1E81jShxtbSh5Hp

Chevelle

I am not leaving out the code for any reason other than to keep this simple.  Below is the section of the code that create the commands that come in from the USB port.  It is parsed in a separate area into a string array which first contains the command and then the applicable parameters.

The commands that are relevant to this are the GetPos and the MoveAbs commands.

If I send a "MoveAbs,0,20000,800" command, the motor moves to position 20000.  The "GetPos,0" command returns 20000 as expected.

If I send a "MoveAbs,0,-20000,800" command, the motor does not move at all but interestingly enough, the "GetPos,0" command returns 4194303.

Code: [Select]

// GET COMMANDS

if (Cmd[0] == "GetPos") {
// Syntax GetPos,Axis(0-1))
if ((Cmd[1].toInt() < 0) || (Cmd[1].toInt() > 1)) { CmdOK =  false; }
if ((CmdOK == true) && (Cmd[1] == "0")) {
strCmd = "Axis0._GetParam(X_ABS_POS) = ";
Serial.print(strCmd);
Serial.print(Axis0._GetParam(x_ABS_POS));
}
if ((CmdOK == true) && (Cmd[1] == "1")) {
strCmd = "Axis1._GetParam(X_ABS_POS) = ";
Serial.print(strCmd);
Serial.println(Axis0._GetParam(x_ABS_POS));
}
}

// SET COMMANDS

if (Cmd[0] == "SetVel") {
// Syntax SetVel,Axis(0-1),Velocity(16-15600)
if ((Cmd[1].toInt() < 0) || (Cmd[1].toInt() > 1)) { CmdOK =  false; }
valInt = Cmd[2].toInt();
if (valInt != constrain(valInt, 16, 15600)) { CmdOK = false; }
if (CmdOK == false) { Serial.println("CmdErr"); }
if ((CmdOK == true) && (Cmd[1] == "0")) {
strCmd = "x_MAX_SPEED, Axis0._MaxSpdCalc(" + Cmd[2] + ")";
Serial.println(strCmd);
Axis0._SetParam(x_MAX_SPEED, Axis0._MaxSpdCalc(Cmd[2].toInt()));
}
if ((CmdOK == true) && (Cmd[1] == "1")) {
strCmd = "x_MAX_SPEED, Axis1._MaxSpdCalc(" + Cmd[2] + ")";
Serial.println(strCmd);
Axis1._SetParam(x_MAX_SPEED, Axis1._MaxSpdCalc(Cmd[2].toInt()));
}
}

if (Cmd[0] == "SetAcc") {
// Syntax SetAcc,Axis(0-1),Acceleration (15-59500)
if ((Cmd[1].toInt() < 0) || (Cmd[1].toInt() > 1)) { CmdOK =  false; }
valInt = Cmd[2].toInt();
if (valInt != constrain(valInt, 15, 59500)) { CmdOK = false; }
if (CmdOK == false) { Serial.println("CmdErr"); }
if ((CmdOK == true) && (Cmd[1] == "0")) {
strCmd = "Axis0._SetParam(x_ACC," +  Cmd[2] + ")";
Serial.println(strCmd);
Axis0._SetParam(x_ACC, Cmd[2].toInt());
}
if ((CmdOK == true) && (Cmd[1] == "1")) {
strCmd = "Axis1._SetParam(x_ACC," + Cmd[2] + ")";
Serial.println(strCmd);
Axis1._SetParam(x_ACC, Cmd[2].toInt());
}
}

if (Cmd[0] == "SetDec") {
// Syntax SetDec,Axis(0-1),Deceleration (15-59500)
if ((Cmd[1].toInt() < 0) || (Cmd[1].toInt() > 1)) { CmdOK = false; }
valInt = Cmd[2].toInt();
if (valInt != constrain(valInt, 15, 59500)) { CmdOK = false; }
if (CmdOK == false) { Serial.println("CmdErr"); }
if ((CmdOK == true) && (Cmd[1] == "0")) {
strCmd = "Axis0._SetParam(x_DEC," + Cmd[2] + ")";
Serial.println(strCmd);
Axis0._SetParam(x_DEC, Cmd[2].toInt());
}
if ((CmdOK == true) && (Cmd[1] == "1")) {
strCmd = "Axis1._SetParam(x_DEC," + Cmd[2] + ")";
Serial.println(strCmd);
Axis1._SetParam(x_DEC, Cmd[2].toInt());
}
}

if (Cmd[0] == "SetStall") {
// Syntax SetStall,Axis,StallCurrent (0-127)
if ((Cmd[1].toInt() < 0) || (Cmd[1].toInt() > 1)) { CmdOK = false; }
valInt = Cmd[2].toInt();
if (valInt != constrain(valInt, 0, 127)) { CmdOK = false; }
if (CmdOK == false) { Serial.println("CmdErr"); }
if ((CmdOK == true) && (Cmd[1] == "0")) {
strCmd = "Axis0._SetParam(x_STALL_TH," + Cmd[2] + ")";
Serial.println(strCmd);
Axis0._SetParam(x_STALL_TH, valInt);
}
if ((CmdOK == true) && (Cmd[1] == "1")) {
strCmd = "Axis1._SetParam(x_STALL_TH," + Cmd[2] + ")";
Serial.println(strCmd);
Axis1._SetParam(x_STALL_TH, valInt);
}
}

if (Cmd[0] == "SetHome") {
// Syntax SetHome,Axis
if ((Cmd[1].toInt() < 0) || (Cmd[1].toInt() > 1)) { CmdOK = false; }
if (CmdOK == false) { Serial.println("CmdErr"); }
if ((CmdOK == true) && (Cmd[1] == "0")) {
strCmd = "Axis0._ResetPos()";
Serial.println(strCmd);
Axis0._ResetPos();
}
if ((CmdOK == true) && (Cmd[1] == "1")) {
strCmd = "Axis1._ResetPos()";
Serial.println(strCmd);
Axis1._ResetPos();
}
}

// MOVE COMMANDS

if (Cmd[0] == "MoveAbs") {
// Syntax MoveAbs,Axis,Steps (+/- 2,000,000),Velocity* (1-15600)
if ((Cmd[1].toInt() < 0) || (Cmd[1].toInt() > 1)) { CmdOK = false; }
valInt = Cmd[3].toInt();
if (valInt != constrain(valInt, 1, 15600)) { CmdOK = false; }
valInt = Cmd[2].toInt();
if (valInt != constrain(valInt, -2000000, 2000000)) { CmdOK = false; }
if (CmdOK == false) { Serial.println("CmdErr"); }
if ((CmdOK == true) && (Cmd[1] == "0")) {
Axis0._SetParam(x_MAX_SPEED, Axis0._MaxSpdCalc(Cmd[3].toInt()));
strCmd = "Axis0._GoTo(" + String(valInt)+ ")";
Serial.print(strCmd);
Axis0._GoTo(valInt);
}
if ((CmdOK == true) && (Cmd[1] == "1")) {
}
}



Chevelle

It looks like your assumption that you could use negative absolute positions is incorrect.  The code only allows for absolute positions between 0 and 0x3FFFFF (4,194,303).
Code: [Select]
// GOTO operates much like MOVE, except it produces absolute motion instead
//  of relative motion. The motor will be moved to the indicated position
//  in the shortest possible fashion.
void cL6470::_GoTo(unsigned long pos)
{

_Data_To_Transfer(x_GOTO);
if (pos > 0x3FFFFF) pos = 0x3FFFFF;
_Data_To_Transfer((byte)(pos >> 16));
_Data_To_Transfer((byte)(pos >> 8));
_Data_To_Transfer((byte)(pos));
}


Exactly my point.

jremington

#13
Aug 10, 2019, 05:59 pm Last Edit: Aug 10, 2019, 06:00 pm by jremington
Your question was answered correctly in reply #1.

Chevelle

Look.  I get it.  Everyone loves to give these pithy terse answers to show how brilliant you are and how ignorant we are but be careful how you play that card.

Yes.  I am well aware of what two's complement is and how to generate the two's complement of a number, i.e reply #1.  What you geniuses can't seem to grasp is that after getting the two's as in reply #1, I can't pass it as an unsigned value because the msb does not lose its significance as a sign bit.

I can get there on my own thank you very much.  It won't elegant or the most direct method that I was hoping to get here from those more knowledgeable than I am but it will work and I'll post it back here for your criticism as well as to pass it on to those who may benefit from it in the future.

Have a nice day.

Go Up