One Teensy 4.1 to send/receive information to six Teensy 4.1s

Status
Not open for further replies.
I commented the aforementioned and the same double frame still occurred.
Code:
 kneeT.enableMBInterrupts();

In regards to the transceiver terminations, they appear correct to me. The Lows and Highs between the CAN Bus transceivers are connected correctly and all the CAN Bus transceiver connections to the Teensy 4.1s match and are identical to each to other.


When lowering the baud rate from 500000 to 125000, the sent frames aren't received. The Serial baud rate is 115200. Would the Serial monitor baud rate being so close the to the CAN Bus baud rate be a reason for dropping frames?
Code:
  primaryT.setBaudRate(500000);


Sending Code:

Code:
// This code is used to send information from Teensy with a CAN Bus towards
// a Teensy with a CAN Bus.

#include <FlexCAN_T4.h>
#include <elapsedMillis.h>

FlexCAN_T4<CAN2, RX_SIZE_256, TX_SIZE_128> primaryT; // Create a constructor with CAN functionality called primaryT.
elapsedMillis tsk1000msCounter;
CAN_message_t message;
int greenLED = 15; // Pin for green LED
int redLED = 14; // Pin for red LED
int state = 0; // To control the amount of messages sent from Primary to receivers.

void setup() {
  primaryT.begin();
  primaryT.setClock(CLK_60MHz);
  primaryT.setBaudRate(500000);
  primaryT.setMaxMB(10);
  primaryT.setMB(MB0, RX);   /* Set Mailbox RX Direction */
  primaryT.setMB(MB1, RX);   /* Set Mailbox RX Direction */
  primaryT.setMB(MB2, RX);   /* Set Mailbox RX Direction */
  for (int i = 4; i < 10; i++) primaryT.setMB((FLEXCAN_MAILBOX)(i), TX); /* Set Mailbox TX Direction */

  message.id = 0x101; // This is the ID for the frame. Primary = 101; HipR = 102; HipL = 103; KneeR = 104; KneeL = 105; AnkleR = 106; AnkleL = 107;
  message.len = 5; // Data length

  Serial.begin(115200); delay(1000);
  primaryT.onReceive(canSniff);
  //primaryT.enableMBInterrupts();
  Serial.print("primaryT Setup: ");
  primaryT.mailboxStatus();
  pinMode(greenLED,OUTPUT);
  pinMode(redLED,OUTPUT);
}

void loop() {
  /*
    if (state == 0) {
      state = 1;
      message.buf[0] = 1; // After 10 seconds, let the motor run.
      digitalWrite(greenLED,HIGH); // Turns the green LED on.
      digitalWrite(redLED,LOW); // Turns the red LED off.
    } else {
      message.buf[0] = 0; // After 10 seconds, pause the motor.
      state = 0;
      digitalWrite(greenLED,LOW); // Turns the green LED off.
      digitalWrite(redLED,HIGH); // Turns the red LED on.
    }
    primaryT.write(message);
    delay(5000);
  */
  
  
  if (tsk1000msCounter >= 2000) {
    Serial.print(tsk1000msCounter);
    tsk1000msCounter = 0;  // Reset millisecond timer
    
    if (state == 0) {
      state = 1;
      message.buf[0] = 1; // After X seconds, let the motor run.
      digitalWrite(greenLED,HIGH); // Turns the green LED on.
      digitalWrite(redLED,LOW); // Turns the red LED off.
    } else {
      state = 0;
      message.buf[0] = 0; // After X seconds, pause the motor.
      digitalWrite(greenLED,LOW); // Turns the green LED off.
      digitalWrite(redLED,HIGH); // Turns the red LED on.
    }
      primaryT.write(message); // Sends the message to CAN
      Serial.print(' ');
      Serial.print(message.buf[0]);
      Serial.println();
  }
  
  
}

void canSniff(const CAN_message_t &msg) {
  Serial.print("MB "); Serial.print(msg.mb);
  Serial.print("  OVERRUN: "); Serial.print(msg.flags.overrun);
  Serial.print("  LEN: "); Serial.print(msg.len);
  Serial.print(" EXT: "); Serial.print(msg.flags.extended);
  Serial.print(" RTR: "); Serial.print(msg.flags.remote);
  Serial.print(" TS: "); Serial.print(msg.timestamp);
  Serial.print(" ID: "); Serial.print(msg.id, HEX);
  Serial.print(" Buffer: ");
  for ( uint8_t i = 0; i < msg.len; i++ ) {
    Serial.print(msg.buf[i], HEX); Serial.print(" ");
  } Serial.println();
  static uint32_t _time = millis();
  Serial.print("Time between frames: ");
  Serial.println(millis() - _time);
  _time = millis();
}

Receiving Code:

Code:
#include <FlexCAN_T4.h>
#include <iostream>
#include <vector>
#include <string.h>
#include <Servo.h>
using namespace std;
using std::vector;

FlexCAN_T4<CAN2, RX_SIZE_256, TX_SIZE_64> kneeT; // Create a constructor with CAN functionality called kneeT.

vector<int> messageData = {0}; // This vector will record incoming messages' data code.

// below are the hip, knee, and ankle average gait cycles for both legs across multiple patients

vector<double> hipData = { 36.45843373, 36.34337349, 36.21204819, 35.81927711, 34.88192771, 33.43493976, 31.65421687, 29.63674699, 27.49638554, 25.32108434, 
23.15722892, 20.98493976, 18.78795181, 16.57650602, 14.35421687, 12.18313253, 10.08012048, 8.055421687, 6.112048193, 4.222891566, 2.389759036, 0.6295180723, 
-1.015060241, -2.506626506, -3.78373494, -4.742168675, -5.255421687, -5.195783133, -4.463253012, -2.888554217, -0.3813253012, 2.972891566, 6.884337349, 11,
15.06686747, 18.93192771, 22.48253012, 25.68012048, 28.47168675, 30.87590361, 32.91566265, 34.6, 35.91686747, 36.85240964, 37.3873494, 37.52168675, 37.28253012, 
36.84096386, 36.40361446, 36.11506024, 35.96204819 };

vector<double> kneeData = { 5.518072289, 7.887951807, 11.02771084, 14.40662651, 17.21204819, 18.94578313, 19.66445783, 19.55722892, 18.9186747, 17.99216867, 16.90421687, 
15.70963855, 14.46325301, 13.20783133, 11.9873494, 10.82710843, 9.759036145, 8.775903614, 7.91746988, 7.225301205, 6.796987952, 6.724096386, 7.123493976, 8.042168675,
9.525903614, 11.63373494, 14.44638554, 18.0746988, 22.60301205, 28.00542169, 34.11626506, 40.60301205, 46.95180723, 52.51024096, 56.75963855, 59.41927711, 60.49216867,
60.04518072, 58.17951807, 55.04216867, 50.76445783, 45.53313253, 39.51686747, 32.90722892, 25.95421687, 19.00421687, 12.61204819, 7.522891566, 4.478915663, 3.826506024,
5.181325301 };

vector<double> ankleData = { -2.145180723, -4.090963855, -5.821084337, -5.834939759, -4.324698795, -2.265060241, -0.2759036145, 1.428915663, 2.871686747, 4.134939759, 5.219277108,
6.124096386, 6.860843373, 7.481325301, 8.036144578, 8.569277108, 9.094578313, 9.593975904, 10.05903614, 10.48192771, 10.8626506, 11.1939759, 11.43373494, 11.45963855,
11.08614458, 10.08614458, 8.101807229, 4.703614458, -0.4301204819, -7.043975904, -13.85180723, -18.85060241, -20.57108434, -19.22710843, -16.18313253, -12.66506024, -9.265662651,
-6.192168675, -3.589759036, -1.497590361, 0.05542168675, 1.087951807, 1.580722892, 1.58313253, 1.137951807, 0.4355421687, -0.3343373494, -0.9879518072, -1.426506024, -1.822289157, 
-2.802409639 };

// We need to convert the data from doubles to integers because our servo motors cannot read the data precisely
// Therefore, integer type vectors with empty elements are made. Vectors can automatically resize.

vector<int> hip = {};
vector<int> knee = {};
vector<int> ankle = {};

// Set the offsets for your starting motor angle, since the motors may not all start at the same position.
int hipOffset = 90;
int kneeOffset = 90;
int ankleOffset = 90;

Servo KneeMotor; // We are creating a constructor called "Knee"
int controlPin = 2; // The data pin from the Teensy to Servo Motor is 2.

// Gait Cycle Stuff goes here:

int cycle = 0; // Start the cycle count at zero.
int gaitType = 1; // Placeholder rn but 1 = normal and all other numbers are abnormal gaits.
int gaitDuration = 1000; // Apparently the average gait cycle for men is between 0.97 to 1.08s. Here, we'll just the since number of 1000 to represent 1 second.
int gaitInterval = gaitDuration / kneeData.size(); // This provides the time between each data point of a gait cycle.

// Since there is a dumb mismatch, we need to setup a ratio to make sure the servo motors actually go to the correct angle.
double motorRatio = 0.6; // Right now, 180 is actually 300 for the servo motor, which means 180/360 = 0.6.

int whiteLED = 33; // Pin for white LED.

void setup(void) {
  Serial.begin(115200); // You want a high baud rate to make sure you pick up all the information you need.
  // Teensy 4.1 is fast enough that there won't be stability issues.
  delay(400); // A moment for the serial to set up before CAN protocols.
  kneeT.begin();
  kneeT.setBaudRate(500000);
  kneeT.setMaxMB(16);
  kneeT.enableFIFO();
  kneeT.enableFIFOInterrupt();
  kneeT.onReceive(canSniff);
  kneeT.mailboxStatus();
  // kneeT.enableMBInterrupts();
  pinMode(whiteLED, OUTPUT); // Sets the white LED as an output.

  KneeMotor.attach(controlPin, 500, 2500); // Allows the MCU to equate the "Knee" to the physical Knee Servo Motor. Also, the 500 is 0 degrees and 2500 is 300 degrees.

  for(int i = 0; i < hipData.size(); i++) { 
    // here the double vectors from the original data are converted to integers
    // every loop changes one element and pushes it back to the new integer vector
    hip.push_back(int(hipData[i]));
    knee.push_back(int(kneeData[i]));
    ankle.push_back(int(ankleData[i]));
  }
  
  // We are using the knee motor here as our example:  
  KneeMotor.write(motorRatio * (hipData[0] + kneeOffset));

  // uncomment the below section if you need to confirm if the data is indeed the same size and to show the data
  /*
  for(int i = 0; i < hip.size(); i++){
    Serial.print(hip[i]);
    Serial.print(" ,");
  }
  Serial.println();
  Serial.println(hip.size());
  for(int i = 0; i < knee.size(); i++){
    Serial.print(knee[i]);
    Serial.print(" ,");
  }
  Serial.println();
  Serial.println(knee.size());
  for(int i = 0; i < ankle.size(); i++){
    Serial.print(ankle[i]);
    Serial.print(" ,");
  }
  Serial.println();
  Serial.println(ankle.size());
  delay(2000); // Time for user to check the readings first before the rest of the program runs
  */

  delay(1000); // Give the motor 1 second to get into position before we run it.

}

void canSniff(const CAN_message_t &msg) {
  Serial.println();
  Serial.print("MB "); Serial.print(msg.mb);
  Serial.print("  OVERRUN: "); Serial.print(msg.flags.overrun);
  Serial.print("  LEN: "); Serial.print(msg.len);
  Serial.print(" EXT: "); Serial.print(msg.flags.extended);
  Serial.print(" RTR: "); Serial.print(msg.flags.remote);
  Serial.print(" TS: "); Serial.print(msg.timestamp);  
  Serial.print(" ID: "); Serial.print(msg.id, HEX);
  Serial.print(" Buffer: ");
  for ( uint8_t i = 0; i < msg.len; i++ ) {
    
    if ( msg.id == 0x101 ) {
      Serial.print(msg.buf[i], HEX); Serial.print(" ");
      messageData[i] = msg.buf[i];
    }
    
  } 
  Serial.println();
  static uint32_t _time = millis();
  Serial.print("Time between frames: ");
  Serial.println(millis() - _time);
  _time = millis();
}


void loop() {
  
  for(int i = 0; i < knee.size(); i++) {
    
    if (messageData[0] == 0) {
      i = i - 1;
      digitalWrite(whiteLED,LOW);
    } else {
      digitalWrite(whiteLED,HIGH);
    }
    
    KneeMotor.write(motorRatio * (hip[i] + kneeOffset));
    Serial.print(messageData[0]); // Print the message stored in messageData vector.
    Serial.print(messageData[1]);
    //Serial.print(hip[i]); // Print the angle the interval and motor output shaft is at.
    Serial.print(", "); // For ease of reading.
    delay(gaitInterval*4); // The motor has trouble catching up to speed, since it takes one second to reach 60 degrees and the knee gait does it in 0.5 seconds.
    
  }
  Serial.println();
  Serial.print("Next Cycle is ");
  Serial.print(cycle); // Will print out which cycle this is.
  Serial.println();
  
  // This is optional but it's demonstrate that the cycle has ended and is returning the cycle back to its starting position.
  /*
  delay(2000); 
  KneeMotor.write(motorRatio * (hip[0] + kneeOffset));
  delay(2000); // Once the motor returns to its original position, the motor can start the gait cycle again.
  */
  
}
 
On Teensy using true USB that Serial baud value has no effect, that param value is ignored. USB transfers happen at best available USB speed - on a T_4,1 that will be using 480 Mbps given host connect at that speed - or 12 Mbps if a slow port or hub is involved.
 
if you cant send or receive at lower CAN speeds than you have set now (provided all nodes use the same speed), there is definately a transceiver/termination issue

No it has no relation to Serial
 
Sorry for not clarifying. The first Teensy on the left is the sending one. It alternates flashing red and green every two seconds if it is sending a frame. The second Teensy from the left is the receiving Teensy. I control them both through a USB hub where I can manually turn on and off the power for them. The rest of the Teensy connections don't matter because I removed the CAN Bus transceiver connections and it didn't made a difference for the duplicating frames.

I even used directly the USB-A 3.2 ports on my laptop individually for each and the receiving Teensy is still receiving duplicate frames.
 
What is so weird is that receiving Teensy says time between frames is 4000ms when the actual time elapsed is 2000ms. Of course, there is the duplicate problem of 1 or 0 ms delay for the second frame.

I want to clarify that the frame sent isn't actually a duplicate, just queued instantly. The first frame send 00000. The second frame sends 01000.
 
Status
Not open for further replies.
Back
Top