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](https://www.lego.com/cdn/cs/set/assets/blt6879b00ae6951482/LEGO_MINDSTORMS_EV3_Communication_Developer_Kit.pdf) (page 24) and [LEGO MINDSTORMS EV3 Firmware Developer Kit](https://www.lego.com/cdn/cs/set/assets/blt77bd61c3ac436ea3/LEGO_MINDSTORMS_EV3_Firmware_Developer_Kit.pdf) (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.  
  
  ---
  
  