Answers.Body: <p>The parameters must be encoded. See section 4.2 in the <em>Communication Developer Kit</em> and section 3.4 in the <em>Firmware Developer Kit</em>.</p>
  <p>Here are the referenced macros from <code>bytecodes.h</code>:</p>
  <pre><code>//        MACROS FOR PRIMITIVES AND SYSTEM CALLS
  
  #define   PRIMPAR_SHORT                 0x00
  #define   PRIMPAR_LONG                  0x80
  
  #define   PRIMPAR_CONST                 0x00
  #define   PRIMPAR_VARIABLE              0x40
  #define   PRIMPAR_LOCAL                 0x00
  #define   PRIMPAR_GLOBAL                0x20
  #define   PRIMPAR_HANDLE                0x10
  #define   PRIMPAR_ADDR                  0x08
  
  #define   PRIMPAR_INDEX                 0x1F
  #define   PRIMPAR_CONST_SIGN            0x20
  #define   PRIMPAR_VALUE                 0x3F
  
  #define   PRIMPAR_BYTES                 0x07
  
  #define   PRIMPAR_STRING_OLD            0
  #define   PRIMPAR_1_BYTE                1
  #define   PRIMPAR_2_BYTES               2
  #define   PRIMPAR_4_BYTES               3
  #define   PRIMPAR_STRING                4
  
  #define   PRIMPAR_LABEL                 0x20
  
  #define   HND(x)                        (PRIMPAR_HANDLE | (x))
  #define   ADR(x)                        (PRIMPAR_ADDR | (x))
  
  #define   LCS                           (PRIMPAR_LONG | PRIMPAR_STRING)
  
  #define   LAB1(v)                       (PRIMPAR_LONG | PRIMPAR_LABEL),((v) &amp; 0xFF)
  
  #define   LC0(v)                        (((v) &amp; PRIMPAR_VALUE) | PRIMPAR_SHORT | PRIMPAR_CONST)
  #define   LC1(v)                        (PRIMPAR_LONG  | PRIMPAR_CONST | PRIMPAR_1_BYTE),((v) &amp; 0xFF)
  #define   LC2(v)                        (PRIMPAR_LONG  | PRIMPAR_CONST | PRIMPAR_2_BYTES),((v) &amp; 0xFF),(((v) &gt;&gt; 8) &amp; 0xFF)
  #define   LC4(v)                        (PRIMPAR_LONG  | PRIMPAR_CONST | PRIMPAR_4_BYTES),((ULONG)(v) &amp; 0xFF),(((ULONG)(v) &gt;&gt; (ULONG)8) &amp; 0xFF),(((ULONG)(v) &gt;&gt; (ULONG)16) &amp; 0xFF),(((ULONG)(v) &gt;&gt; (ULONG)24) &amp; 0xFF)
  
  #define   LV0(i)                        (((i) &amp; PRIMPAR_INDEX) | PRIMPAR_SHORT | PRIMPAR_VARIABLE | PRIMPAR_LOCAL)
  #define   LV1(i)                        (PRIMPAR_LONG  | PRIMPAR_VARIABLE | PRIMPAR_LOCAL | PRIMPAR_1_BYTE),((i) &amp; 0xFF)
  #define   LV2(i)                        (PRIMPAR_LONG  | PRIMPAR_VARIABLE | PRIMPAR_LOCAL | PRIMPAR_2_BYTES),((i) &amp; 0xFF),(((i) &gt;&gt; 8) &amp; 0xFF)
  #define   LV4(i)                        (PRIMPAR_LONG  | PRIMPAR_VARIABLE | PRIMPAR_LOCAL | PRIMPAR_4_BYTES),((i) &amp; 0xFF),(((i) &gt;&gt; 8) &amp; 0xFF),(((i) &gt;&gt; 16) &amp; 0xFF),(((i) &gt;&gt; 24) &amp; 0xFF)
  
  #define   GV0(i)                        (((i) &amp; PRIMPAR_INDEX) | PRIMPAR_SHORT | PRIMPAR_VARIABLE | PRIMPAR_GLOBAL)
  #define   GV1(i)                        (PRIMPAR_LONG  | PRIMPAR_VARIABLE | PRIMPAR_GLOBAL | PRIMPAR_1_BYTE),((i) &amp; 0xFF)
  #define   GV2(i)                        (PRIMPAR_LONG  | PRIMPAR_VARIABLE | PRIMPAR_GLOBAL | PRIMPAR_2_BYTES),((i) &amp; 0xFF),(((i) &gt;&gt; 8) &amp; 0xFF)
  #define   GV4(i)                        (PRIMPAR_LONG  | PRIMPAR_VARIABLE | PRIMPAR_GLOBAL | PRIMPAR_4_BYTES),((i) &amp; 0xFF),(((i) &gt;&gt; 8) &amp; 0xFF),(((i) &gt;&gt; 16) &amp; 0xFF),(((i) &gt;&gt; 24) &amp; 0xFF)
  </code></pre>
  <p>Values withing the range 0 to 31 can essentially be passed directly since <code>PRIMPAR_SHORT</code> and <code>PRIMPAR_CONST</code> used in <code>LC0()</code> are both 0 (values -31 to -1 can also be used as LC0 but need to be bitwise and-ed with 0x3F). But since the speeds can be +/-100, they need <code>LC1()</code> which requires two bytes.</p>
  <p>So something like this?</p>
  <pre><code>ByteBuffer
      .allocate(20)
      .order(ByteOrder.LITTLE_ENDIAN)
      .putShort(18) // command size
      .putShort(0) // message counter
      .put(0x80.toByte()) // direct command, no reply
      .putShort(0) // globals/locals
      .put(0xA5.toByte()) // opOutput_Speed
      .put(0) // LAYER=LC0(0)
      .put(0b01) // NOS=LC0(1)
      .put(0x81).put(leftSpeed.toByte()) // SPEED=LC1(leftSpeed)
      .put(0xA5.toByte()) // opOutput_Speed
      .put(0) // LAYER=LC0(0)
      .put(0b10) // NOS=LC0(2)
      .put(0x81).put(rightSpeed.toByte()) // SPEED=LC1(rightSpeed)
      .put(0xA6.toByte()) // opOutput_Start
      .put(0) // LAYER=LC0(0)
      .put(0b11) // NOS=LC0(3)
  </code></pre>
  
Answers.ContentLicense: CC BY-SA 4.0
Answers.CreationDate: 2023-05-09T23:41:36.707Z
Answers.Text: First of all, I really appreciate your response. I am not familiar with the encoding, did I get this right? For each argument, if its range (signed) is within +/- 31 I should pass it through the LC0 macro, if it's +/- 127 I should pass it through the LC1 macro and so on? and that means that the encoded speed is actually 2 bytes?
Answers.UserDisplayName: interacsion
Answers.ContentLicense: CC BY-SA 4.0
Answers.CreationDate: 2023-05-10T13:49:09.753Z
Answers.Text: Yes, that is correct.
Answers.UserDisplayName: David Lechner
Answers.ContentLicense: CC BY-SA 4.0
Answers.CreationDate: 2023-05-09T22:42:53.300Z
Answers.LastActivityDate: 2023-10-01T21:35:43.650Z
Answers.LastEditDate: 2023-10-01T21:35:43.650Z
Answers.UserDisplayName: David Lechner
Body: <p>I am trying to set a EV3 motor's speed and start it remotely using a direct command. Using the resources <a href="https://www.lego.com/cdn/cs/set/assets/blt6879b00ae6951482/LEGO_MINDSTORMS_EV3_Communication_Developer_Kit.pdf" rel="nofollow noreferrer">LEGO MINDSTORMS EV3 Communication Developer Kit</a> (page 24) and <a href="https://www.lego.com/cdn/cs/set/assets/blt77bd61c3ac436ea3/LEGO_MINDSTORMS_EV3_Firmware_Developer_Kit.pdf" rel="nofollow noreferrer">LEGO MINDSTORMS EV3 Firmware Developer Kit</a> (page 53) I've came up with the following (Kotlin) code to create the command:</p>
  <pre><code>ByteBuffer
      .allocate(18)
      .order(ByteOrder.LITTLE_ENDIAN)
      .putShort(16)
      .putShort(0)
      .put(0x80.toByte())
      .putShort(0)
      .put(0xA5.toByte())
      .put(0)
      .put(0b01)
      .put(leftSpeed.toByte())
      .put(0xA5.toByte())
      .put(0)
      .put(0b10)
      .put(rightSpeed.toByte())
      .put(0xA6.toByte())
      .put(0)
      .put(0b11)
  </code></pre>
  <p>However, the EV3 behaves really unpredictably, with some speed values (the range is -100 to 100) flipping the polarity, some even crashing the OS.</p>
  
Tags: <ev3><programming>
Title: Direct command to set EV3 motor speed
UserDisplayName: interacsion
ThreadText: # Direct command to set EV3 motor speed
  
  (Asked by: username_0 on 2023-05-09)
  
  I am trying to set a EV3 motor's speed and start it remotely using a direct command. Using the resources LEGO MINDSTORMS EV3 Communication Developer Kit (page 24) and LEGO MINDSTORMS EV3 Firmware Developer Kit (page 53) I've came up with the following (Kotlin) code to create the command:
  ByteBuffer
      .allocate(18)
      .order(ByteOrder.LITTLE_ENDIAN)
      .putShort(16)
      .putShort(0)
      .put(0x80.toByte())
      .putShort(0)
      .put(0xA5.toByte())
      .put(0)
      .put(0b01)
      .put(leftSpeed.toByte())
      .put(0xA5.toByte())
      .put(0)
      .put(0b10)
      .put(rightSpeed.toByte())
      .put(0xA6.toByte())
      .put(0)
      .put(0b11)
  
  However, the EV3 behaves really unpredictably, with some speed values (the range is -100 to 100) flipping the polarity, some even crashing the OS.
  
  **Tags:** ev3, programming
  
  ---
  
  ## 1 answers
  
  ### Answer by username_1 on 2023-05-09. Score: 3 | Accepted answer
  
  The parameters must be encoded. See section 4.2 in the Communication Developer Kit and section 3.4 in the Firmware Developer Kit.
  Here are the referenced macros from bytecodes.h:
  //        MACROS FOR PRIMITIVES AND SYSTEM CALLS
  
  #define   PRIMPAR_SHORT                 0x00
  #define   PRIMPAR_LONG                  0x80
  
  #define   PRIMPAR_CONST                 0x00
  #define   PRIMPAR_VARIABLE              0x40
  #define   PRIMPAR_LOCAL                 0x00
  #define   PRIMPAR_GLOBAL                0x20
  #define   PRIMPAR_HANDLE                0x10
  #define   PRIMPAR_ADDR                  0x08
  
  #define   PRIMPAR_INDEX                 0x1F
  #define   PRIMPAR_CONST_SIGN            0x20
  #define   PRIMPAR_VALUE                 0x3F
  
  #define   PRIMPAR_BYTES                 0x07
  
  #define   PRIMPAR_STRING_OLD            0
  #define   PRIMPAR_1_BYTE                1
  #define   PRIMPAR_2_BYTES               2
  #define   PRIMPAR_4_BYTES               3
  #define   PRIMPAR_STRING                4
  
  #define   PRIMPAR_LABEL                 0x20
  
  #define   HND(x)                        (PRIMPAR_HANDLE | (x))
  #define   ADR(x)                        (PRIMPAR_ADDR | (x))
  
  #define   LCS                           (PRIMPAR_LONG | PRIMPAR_STRING)
  
  #define   LAB1(v)                       (PRIMPAR_LONG | PRIMPAR_LABEL),((v) & 0xFF)
  
  #define   LC0(v)                        (((v) & PRIMPAR_VALUE) | PRIMPAR_SHORT | PRIMPAR_CONST)
  #define   LC1(v)                        (PRIMPAR_LONG  | PRIMPAR_CONST | PRIMPAR_1_BYTE),((v) & 0xFF)
  #define   LC2(v)                        (PRIMPAR_LONG  | PRIMPAR_CONST | PRIMPAR_2_BYTES),((v) & 0xFF),(((v) >> 8) & 0xFF)
  #define   LC4(v)                        (PRIMPAR_LONG  | PRIMPAR_CONST | PRIMPAR_4_BYTES),((ULONG)(v) & 0xFF),(((ULONG)(v) >> (ULONG)8) & 0xFF),(((ULONG)(v) >> (ULONG)16) & 0xFF),(((ULONG)(v) >> (ULONG)24) & 0xFF)
  
  #define   LV0(i)                        (((i) & PRIMPAR_INDEX) | PRIMPAR_SHORT | PRIMPAR_VARIABLE | PRIMPAR_LOCAL)
  #define   LV1(i)                        (PRIMPAR_LONG  | PRIMPAR_VARIABLE | PRIMPAR_LOCAL | PRIMPAR_1_BYTE),((i) & 0xFF)
  #define   LV2(i)                        (PRIMPAR_LONG  | PRIMPAR_VARIABLE | PRIMPAR_LOCAL | PRIMPAR_2_BYTES),((i) & 0xFF),(((i) >> 8) & 0xFF)
  #define   LV4(i)                        (PRIMPAR_LONG  | PRIMPAR_VARIABLE | PRIMPAR_LOCAL | PRIMPAR_4_BYTES),((i) & 0xFF),(((i) >> 8) & 0xFF),(((i) >> 16) & 0xFF),(((i) >> 24) & 0xFF)
  
  #define   GV0(i)                        (((i) & PRIMPAR_INDEX) | PRIMPAR_SHORT | PRIMPAR_VARIABLE | PRIMPAR_GLOBAL)
  #define   GV1(i)                        (PRIMPAR_LONG  | PRIMPAR_VARIABLE | PRIMPAR_GLOBAL | PRIMPAR_1_BYTE),((i) & 0xFF)
  #define   GV2(i)                        (PRIMPAR_LONG  | PRIMPAR_VARIABLE | PRIMPAR_GLOBAL | PRIMPAR_2_BYTES),((i) & 0xFF),(((i) >> 8) & 0xFF)
  #define   GV4(i)                        (PRIMPAR_LONG  | PRIMPAR_VARIABLE | PRIMPAR_GLOBAL | PRIMPAR_4_BYTES),((i) & 0xFF),(((i) >> 8) & 0xFF),(((i) >> 16) & 0xFF),(((i) >> 24) & 0xFF)
  
  Values withing the range 0 to 31 can essentially be passed directly since PRIMPAR_SHORT and PRIMPAR_CONST used in LC0() are both 0 (values -31 to -1 can also be used as LC0 but need to be bitwise and-ed with 0x3F). But since the speeds can be +/-100, they need LC1() which requires two bytes.
  So something like this?
  ByteBuffer
      .allocate(20)
      .order(ByteOrder.LITTLE_ENDIAN)
      .putShort(18) // command size
      .putShort(0) // message counter
      .put(0x80.toByte()) // direct command, no reply
      .putShort(0) // globals/locals
      .put(0xA5.toByte()) // opOutput_Speed
      .put(0) // LAYER=LC0(0)
      .put(0b01) // NOS=LC0(1)
      .put(0x81).put(leftSpeed.toByte()) // SPEED=LC1(leftSpeed)
      .put(0xA5.toByte()) // opOutput_Speed
      .put(0) // LAYER=LC0(0)
      .put(0b10) // NOS=LC0(2)
      .put(0x81).put(rightSpeed.toByte()) // SPEED=LC1(rightSpeed)
      .put(0xA6.toByte()) // opOutput_Start
      .put(0) // LAYER=LC0(0)
      .put(0b11) // NOS=LC0(3)
  
  > **Comments:**
  > **username_0**: First of all, I really appreciate your response. I am not familiar with the encoding, did I get this right? For each argument, if its range (signed) is within +/- 31 I should pass it through the LC0 macro, if it's +/- 127 I should pass it through the LC1 macro and so on? and that means that the encoded speed is actually 2 bytes?  
  > **username_1**: Yes, that is correct.  
  
  ---
  
  