Go Down

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

#### Chevelle

##### Aug 10, 2019, 02:44 pm
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

#1
##### Aug 10, 2019, 02:46 pm
Two's complement - invert, and add one.

#### GolamMostafa

#2
##### Aug 10, 2019, 03:21 pmLast 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 pmLast 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

#4
##### Aug 10, 2019, 03:34 pm
In the code below, if valInt is -20,000

Code: [Select]
`if (valInt < 0) { valInt =  ~valInt + B01; }    Serial.println(valInt, BIN);  // shows 1011000111100000Serial.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

#5
##### Aug 10, 2019, 03:40 pm
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

#6
##### Aug 10, 2019, 03:41 pm
Quote
shows 20000 but should show 45536
It isn't possible to represent 45536 in a signed sixteen bit value.

#### Chevelle

#7
##### Aug 10, 2019, 03:41 pm
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

#8
##### Aug 10, 2019, 03:45 pm
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

#9
##### Aug 10, 2019, 03:48 pm
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

#10
##### Aug 10, 2019, 03:58 pm
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

#11
##### Aug 10, 2019, 04:08 pm
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

#12
##### Aug 10, 2019, 04:32 pm
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.

#13

#### Chevelle

#14
##### Aug 10, 2019, 07:04 pm
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