Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

CAN library and .ino test code upload #5

Open
wants to merge 1 commit into
base: main
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
196 changes: 196 additions & 0 deletions ESP32LowLevel/CAN.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,196 @@
#include "CAN.h"

#include <cstring>
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think this is not needed. Could you please verify it?


#define CAN_ID 0x11 // this shouldn't be here in the end but specified in the makefile
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
#define CAN_ID 0x11 // this shouldn't be here in the end but specified in the makefile

As you noted this should not be here. As for tests you can define temporarily #define MOD_HEAD in mod_config.h but this should not be pushed to production



//
CAN::CAN() {}

// I
void CAN::init() {
// configure CAN
CAN0.setCANPins((gpio_num_t)36, (gpio_num_t)35);
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This PINs can go to the definition file IMHO

CAN0.begin(125000);
Copy link
Member

@luca-byte luca-byte Dec 27, 2024

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This (the bitrate) can be a parameter in the CAN.h class

CAN0.watchFor(); // use this to filter for specific IDs
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Question: at the moment the CAN is not filtering messages? If this is the case, it is problematic because it could enact on commands meant for other modules


// DEBUG
Serial.println("Can init...");
}
Comment on lines +18 to +20
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This is okay, it will be integrated into the debug logging system




// send motor feedback
void CAN::sendMotorFeedback() {
canMsg.id = 0; // Reset
canMsg.id = CAN_ID | (MOTOR_FEEDBACK_ID << 16);
canMsg.length = 8;
canMsg.rtr = 0;
canMsg.extended = 1;
// send motor feedback as float

// in the end, uncomment these two lines and delete the two test values
//float speedR = motorTrRight.getSpeed();
//float speedL = motorTrLeft.getSpeed();
float speedR = 2.0;
float speedL = 3.5;
Comment on lines +33 to +37
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actually this is not correct: the main board does not use SmartMotor because the motors are controlled by the MotorsBoard. The code will need to obtain the data by I2C from the MotorsBoard

memcpy(&canMsg.data.uint8[0], &speedL, 4);
memcpy(&canMsg.data.uint8[4], &speedR, 4);
Comment on lines +38 to +39
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Here there is probably some redundant pointer arithmetic, but it is not a problem. However I would prefer the code to be consistent (see the setpoint)


CAN0.sendFrame(canMsg);
}


void CAN::sendJointFeedback() {
// in the end, uncomment these two lines and delete the test value
//encoderYaw.update();
//float angle = encoderYaw.readAngle();
float angle = 7;
Comment on lines +48 to +49
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

How are we passing the encoderYaw object to this method?

canMsg.id = 0;
canMsg.id = CAN_ID | (JOINT_YAW_FEEDBACK_ID << 16);
canMsg.length = 4;
canMsg.rtr = 0;
canMsg.extended = 1;
memcpy(canMsg.data.uint32, &angle, 4);
CAN0.sendFrame(canMsg);

}



// send end effector's feedback
void CAN::sendEndEffectorFeedback() {
// in the end, uncomment this line and delete the test value
// int pitch = motorEEPitch.readPosition();
int pitch = 1;
canMsg.id = 0; // Reset
canMsg.id = CAN_ID | (END_EFFECTOR_PITCH_FEEDBACK_ID << 16);
canMsg.length = 4;
canMsg.rtr = 0;
canMsg.extended = 1;
memcpy(canMsg.data.uint8, &pitch, 4);
CAN0.sendFrame(canMsg);

// in the end, uncomment this line and delete the test value
//int headPitch = motorEEHeadPitch.readPosition();
int headPitch = 1;

canMsg.id = CAN_ID | (END_EFFECTOR_HEAD_PITCH_FEEDBACK_ID << 16);
canMsg.length = 4;
canMsg.rtr = 0;
canMsg.extended = 1;
memcpy(canMsg.data.uint8, &headPitch, 4);
CAN0.sendFrame(canMsg);

// in the end, uncomment this line and delete the test value
//int headRoll = motorEEHeadRoll.readPosition();
int headRoll = 1;
canMsg.id = CAN_ID | (END_EFFECTOR_HEAD_ROLL_FEEDBACK_ID << 16);
canMsg.length = 4;
canMsg.rtr = 0;
canMsg.extended = 1;
memcpy(canMsg.data.uint8, &headRoll, 4);
CAN0.sendFrame(canMsg);

}

bool CAN::receiveMotorSetpoint() {
// take the first four bytes from the array and and put them in a float
float leftSpeed, rightSpeed;
memcpy(&leftSpeed, canMsg.data.uint8, 4); // Copia i primi 4 byte per leftSpeed
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Comments should be in english

memcpy(&rightSpeed, canMsg.data.uint8 + 4, 4);
// in the end, uncomment these two lines
//motorTrLeft.setSpeed(leftSpeed);
//motorTrRight.setSpeed(rightSpeed);
Comment on lines +103 to +105
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actually using I2C also here

}





bool CAN::receiveJointSetpoint() {
float yawA;
memcpy(&yawA, canMsg.data.uint8, 4);
// to be completed
}



// receive end effector setpoint
bool CAN::receiveEndEffectorSetpoint(byte type) {
int16_t data;

switch (type) {
case END_EFFECTOR_PITCH_SETPOINT_ID:
// take the first four bytes from the array and and put them in a float
memcpy(&data, canMsg.data.uint8, 4);
// in the end, uncomment this line
//motorEEPitch.moveSpeed(data, SERVO_SPEED);
break;
break;
case END_EFFECTOR_HEAD_PITCH_SETPOINT_ID:
// take the first four bytes from the array and and put them in a float
memcpy(&data, canMsg.data.uint8, 4);
// in the end, uncomment this line
//motorEEPitch.moveSpeed(data, SERVO_SPEED);

break;
case END_EFFECTOR_HEAD_ROLL_SETPOINT_ID:
// take the first four bytes from the array and and put them in a float
memcpy(&data, canMsg.data.uint8, 4);
// in the end, uncomment this line
//motorEEPitch.moveSpeed(data, SERVO_SPEED);

break;
}
}

bool CAN::receiveMessage() {
unsigned long time_cur = millis(); // current time
if (CAN0.read(canMsg)) {
time_data = time_cur;
byte type = canMsg.id >> 16;


// DEBUG: print frame
Serial.println("I'm receiving...");
Serial.print(canMsg.id, HEX);
if (canMsg.extended) {
Serial.print(" X ");}
else {
Serial.print(" S "); }
Serial.print(canMsg.length, DEC);
for (int i = 0; i < canMsg.length; i++) {
Serial.print(canMsg.data.byte[i], HEX);
Serial.print(" ");}
Serial.println();
Comment on lines +156 to +167
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This will go to the Debug class, but is ok



if (type == MOTOR_SETPOINT_ID) {
receiveMotorSetpoint();
}
else if (type == END_EFFECTOR_PITCH_SETPOINT_ID ||
type == END_EFFECTOR_HEAD_PITCH_SETPOINT_ID ||
type == END_EFFECTOR_HEAD_ROLL_SETPOINT_ID) {
receiveEndEffectorSetpoint(type);
}
else if (type == JOINT_YAW_SETPOINT_ID) {
receiveJointSetpoint();
}

return true;
}
Comment on lines +170 to +183
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

what about a switch-case?

Suggested change
if (type == MOTOR_SETPOINT_ID) {
receiveMotorSetpoint();
}
else if (type == END_EFFECTOR_PITCH_SETPOINT_ID ||
type == END_EFFECTOR_HEAD_PITCH_SETPOINT_ID ||
type == END_EFFECTOR_HEAD_ROLL_SETPOINT_ID) {
receiveEndEffectorSetpoint(type);
}
else if (type == JOINT_YAW_SETPOINT_ID) {
receiveJointSetpoint();
}
return true;
}
switch (type) {
case MOTOR_SETPOINT_ID:
receiveMotorSetpoint();
break;
case END_EFFECTOR_PITCH_SETPOINT_ID:
case END_EFFECTOR_HEAD_PITCH_SETPOINT_ID:
case END_EFFECTOR_HEAD_ROLL_SETPOINT_ID:
receiveEndEffectorSetpoint(type);
break;
case JOINT_YAW_SETPOINT_ID:
receiveJointSetpoint();
break;
}
return true;
}

// Timeout
else if (time_cur - time_data > TIMEOUT && time_data != 0) {
time_data = -1;

//DEBUG
Serial.println("Timeout reached.");
// in the end, uncomment these two lines
// motorTrLeft.stop();
// motorTrRight.stop();
Comment on lines +191 to +192
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

see above

}

return false; // No msg received
}
62 changes: 62 additions & 0 deletions ESP32LowLevel/CAN.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,62 @@
/*
Using https://github.com/collin80/esp32_can
which requires https://github.com/collin80/can_common
Install both by downloading the ZIP file from GitHub.

*/

#include <esp32_can.h>
Comment on lines +1 to +8
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

If these are file we need to copy (not installable using the Arduino IDE) I think that we can copy them directly in the codebase in this folder

#include "mod_config.h"
#ifndef CAN_H
#define CAN_H




class CAN {
public:
// Constructor
CAN();

// Configure CAN
void init();

// send messages
void sendMotorFeedback();
void sendJointFeedback();
void sendEndEffectorFeedback();

// receive messages
bool receiveMessage();
bool receiveMotorSetpoint();
bool receiveJointSetpoint();
bool receiveEndEffectorSetpoint(byte type);

private:
CAN_FRAME canMsg;
unsigned long time_data = -1;
const unsigned long TIMEOUT = 1000;

// this enum cointains all message IDs (to be sent and to be received)
enum MessageID {
MOTOR_SETPOINT_ID = 0x21,
MOTOR_FEEDBACK_ID = 0x22,
JOINT_YAW_SETPOINT_ID = 0x31,
JOINT_YAW_FEEDBACK_ID = 0x32,
//JOINT_PITCH_SETPOINT_ID = 0x33,
//JOINT_PITCH_FEEDBACK_ID = 0x34,
//JOINT_ROLL_SETPOINT_ID = 0x35,
//JOINT_ROLL_FEEDBACK_ID = 0x36,
END_EFFECTOR_PITCH_SETPOINT_ID = 0x41,
END_EFFECTOR_PITCH_FEEDBACK_ID = 0x42,
END_EFFECTOR_HEAD_PITCH_SETPOINT_ID = 0x43,
END_EFFECTOR_HEAD_PITCH_FEEDBACK_ID = 0x44,
END_EFFECTOR_HEAD_ROLL_SETPOINT_ID = 0x45,
END_EFFECTOR_HEAD_ROLL_FEEDBACK_ID = 0x46,

};


};

#endif // CAN_H
30 changes: 30 additions & 0 deletions ESP32LowLevel/mod_config.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
#ifndef module_configuration_h
#define module_configuration_h

// MOD_HEAD, MOD_MIDDLE, MOD_TAIL are defined in the makefile


#if defined(MOD_HEAD)
#define CAN_ID 0x11 // HEAD
#define MODC_EE
#define SERVO_EE_PITCH_ID 6
#define SERVO_EE_HEAD_ROLL_ID 4
#define SERVO_EE_HEAD_PITCH_ID 2
#define SERVO_SPEED 200

#elif defined(MOD_MIDDLE)
#define CAN_ID 0x12 // MIDDLE
#define MODC_YAW

#elif defined(MOD_TAIL)
#define CAN_ID 0x13 // TAIL
#define MODC_YAW
#define MODC_PITCH
#define SERVO_A_ID 5
#define SERVO_B_ID 1
#define SERVO_MIN 200
#define SERVO_MAX 800
#define SERVO_SPEED 200
#endif

#endif
31 changes: 31 additions & 0 deletions ESP32LowLevel/testCan.ino
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
/*
Using https://github.com/collin80/esp32_can
which requires https://github.com/collin80/can_common
Install both by downloading the ZIP file from GitHub.
*/

/*
This code must include SmartMotor.h (and the libraries included in it) to be completed.
At the moment it sends fixed values and received ones do not update anything.
*/

#include "CAN.h"


CAN canBus;

void setup() {
Serial.begin(115200);
canBus.init();

}

void loop() {
// receiving setpoints
canBus.receiveMessage();

// sending feedback
canBus.sendMotorFeedback();
canBus.sendJointFeedback();
canBus.sendEndEffectorFeedback();
}