Friday 12 April 2013

A serial MultiWii controller

With two working Nunchuks connected to our Arduino (see last post), we could continue building our RC controller.

 

1. Converting Nunchuk data into RC signals

We grabbed MultiWii v2.2 from here (the latest release as of this writing), and examined it to determine what kind of RC input it expects. MultiWii expects RC serial messages to contain 8 16-bit integers containing values between 1000 and 2000. PWM signals for servos and ESCs typically vary between 1000µs and 2000µs. Presumably, the RC values are simply the pulse-widths which would be read from the PWM input if the quadcopter was being controlled by a traditional RC radio. The 8 signals are: roll, pitch, yaw, throttle, aux1, aux2, aux3, and aux4.

In our case, the Arduino simply maps the 4 Nunchuk axis onto roll, pitch, yaw, and throttle. We used the normal axis layout for RC helicopters, known as Mode II.

The single complication in this part of the code is the throttle axis. In RC radios, the throttle is at rest at the down position, whereas the other three axis are at rest at the center position. Furthermore, the throttle in RC radios is not sprung, so it does not return to its rest position on its own. We would need to modify out Nunchuk to make the throttle operate in this way. We can compromise however, on the zero-point. We mapped the throttle such that only the top half of the stick is the active range, as shown:


This makes the throttle behave more like an RC radio controller.

As an optional safety precaution, the throttle is only active when both Nunchuks' Z buttons are held down. We chose to do this because it is so easy to accidentally bump the little Nunchuk joysticks.

2. Sending RC signals to MultiWii

Unfortunately, the MultiWii serial protocol (MSP) is described in this form post is vague. We decided to find some existing code which implements the MSP and examine it as a reference. The best existing code which does this is the MultiWii configuration program, which comes with MultiWii. It is written in Processing. Based on the Processing code and the MultiWii source code itself, we determined that MSP data frames are structured as follows:


The configuration program assembled these messages using the following function:

//send msp with payload
private List<byte> requestMSP (int msp, Character[] payload) {
  if(msp < 0) {
   return null;
  }
  List<byte> bf = new LinkedList<byte>();
  for (byte c : MSP_HEADER.getBytes()) {
    bf.add( c );
  }
   
  byte checksum=0;
  byte pl_size = (byte)((payload != null ? int(payload.length) : 0)&0xFF);
  bf.add(pl_size);
  checksum ^= (pl_size&0xFF);
   
  bf.add((byte)(msp & 0xFF));
  checksum ^= (msp&0xFF);
   
  if (payload != null) {
    for (char c :payload){
      bf.add((byte)(c&0xFF));
      checksum ^= (c&0xFF);
    }
  }
  bf.add(checksum);
  return (bf);
}

We re-implemented this function in Arduino like so:

// Send a message using the MultiWii serial protocol.
void send_msp(uint8_t opcode, uint8_t * data, uint8_t n_bytes) {
  uint8_t checksum = 0;
  
  // Send the MSP header and message length
  Serial.write((byte *)"$M<", 3);
  Serial.write(n_bytes);
  checksum ^= n_bytes;

  // Send the op-code
  Serial.write(opcode);
  checksum ^= opcode;
  
  // Send the data bytes
  for(int i = 0; i < n_bytes; i++) {
    Serial.write(data[i]);
    checksum ^= data[i];
  }
  
  // Send the checksum
  Serial.write(checksum);
}

The MSP message which sends RC data is called MSP_SET_RAW_RC and has message type 200. It is composed of 16 bytes which represent 8 16-bit integers. We trivially translated our control signals from Step 1 into an array of bytes, and send it using the function above. For now, we're sending zero for aux1-aux4.

When our control board arrives we will test and debug our code, and post a complete Arduino sketch.

10 comments:

  1. Hi there,

    My lab partner and I are trying to do a similar thing with our quadcopter, and were wondering if you were able to get this to work with your Xbee's for RC communication.

    Thanks for any advice,

    Evan

    ReplyDelete
    Replies
    1. Yep, it's all working fine. New post coming soon with details and full code.

      Delete
    2. We've just posted our code. More details to come early this week.

      Delete
  2. Have you tried already???

    Seems very interesting to have more MW serial protocol stuff, because reading the processing file is actually a pain in the a$%^$ hehehehe

    Good job!!

    ReplyDelete
    Replies
    1. Yup, I just made a new post with code. More details to come soon!

      Delete
  3. Normally we need to arm the motors in order to start through the MW FC. Do we require to do that incase I am injecting th/pitch/roll/yaw values through the Serial port or not?

    ReplyDelete
  4. This comment has been removed by a blog administrator.

    ReplyDelete
  5. Hi there,
    I need to design the packets to send it to the quad.Can you just tell me in which format we should send the message ID,no of bytes and data (ASCII,HEX,Binary,Decimal?
    My Packet of data is like this :$M<A16200100010001000100020001000100010000 In this iam setting all roll,pitch,yaw,throttle,all AUXs except AUX1 as 1000& AUX1 as 2000 Am I correct?

    Please do reply as soon as possible.

    Thanks in Advance

    Bala

    ReplyDelete
    Replies
    1. Hi there, Can you design the packets to send it to Drone right? Can you just tell me about how to design it please. thank you :)

      Delete
    2. We send the bytes in the following order:
      (roll, throttle, yaw, pitch, 0, 0, 0, 0)
      We format the bytes into a message using the send_msp() function above.

      More info coming soon.
      Meanwhile... http://microquad.blogspot.ca/2017/10/teaser-project-revived.html

      Delete