Close

Redesigning Nextion HMI library

A project log for Building the Thor robot

Building a 6-axis robot based on the Thor robot. When size DOES matter!

olaf-baeyensOlaf Baeyens 10/02/2017 at 15:560 Comments

The Nextion HMI display library is good but for my Thor implementation too generic and not good enough for lots of controls, speed and reliability.

So I have chosen to redesign the library so in the end I have a more compact code and optimal (communication) for the Thor robot.

This code will evolve as it is being designed.


First the Nextion HMI editor project

We are designing a screen that have 7 enable buttons and beneath these buttons we have 2 rotation buttons. The original Nextion library code would have too many callbacks and hacks for what I have in mind.

I want to make sure that the connection Thor - Nextion HMI display is being monitored and that the Thor main controller can detect a HMI display that is giving wrong commands or unresponsive.

I also want the Thor robot controller library to be created more intelligently.

This screen show that for Page 1, we have a dual state button that will be programmed to enable and disable the rotating buttons below if it si active or not. This code demonstrates that we copy the bitmap under bitmap 2/3 (green/red active button) or 1 (disabled button)

This code runs on the HMI display only and does not burden the  Thor robot controller with too much communication.

The button has the "Send Component ID"  checked for both the Touch Press event and the Touch Release event. This will send a serial command to the Thor controller when pressed and depressed.

(If you look at this example, I have shortened the names and there is a reason for this. When I read in properties for this control from the Thor robot controller, the complete name is being transmitted which means longer transmission times and responses.

The button "Send Component ID" is seen below

The "Send Component ID" is a start byte indicating that we have a "Button" command, then followed with a page ID, the Control ID and a value 0 if it is depressed or 1 if it is pressed. It completes with 2x255 bytes marking the end of a command.

No properties of that control is being transmitted, that is not part of the current code I want to redesign yet.

This primary goal is to send make the Thor robot step the motor in a left or right direction and immediately stops when I release the button.

The Nextion Library has a call back method that you attach to a Pop (release button) and Push (press button) event.  I want to have only one callback for starting.

Which is defined below:

typedef void(*TouchEventButton)(byte page, byte button, byte pressed);

 The callback should be used as in example below:

void ButtonPress_Callback(byte page, byte button, byte pressed) {
	if (page == 1) {
                // Check on button MR_E0L (Motor Rotate E0 channel Left direction)
		if (button == MR_E0L) {
                        // I always check on value 0, only 0 = false anything else is true
			if (pressed != 0) {
				digitalWrite(LED_BUILTIN, HIGH);
			}
			else {
				digitalWrite(LED_BUILTIN, LOW);
			}
		}
	}
} 

This callback can now be much easier to extend, but also used as a very basic.

The callback should be processed in the Arduino Loop() method.

void loop() {
	// process incoming Nextion button presses
	display_loop(ButtonPress_Callback);
}

Initialization is done like this:

Choose the COM1 channel (you have Serial, Serial1, Serial 2, Serial 3)

#define nexSerial Serial1

Initialize the display, and set it to page "0"

bool display_init(void) {
	nexSerial.begin(9600);
	displaySendCommand("");
	displaySendCommand("bkcmd=1");
	bool ret1 = displayRetCommandFinished(1000);
	displaySendCommand("page 0");
	bool ret2 = displayRetCommandFinished(1000);
	return ret1 && ret2;
}
void displaySendCommand(const char* cmd) {
	clear_buffer();
	// Send command 
	nexSerial.print(cmd);
	nexSerial.write(0xFF);
	nexSerial.write(0xFF);
	nexSerial.write(0xFF);
}
void clear_buffer() {
	// Clear buffer
	while (nexSerial.available()) {
		nexSerial.read();
	}
}

The functional code to listen to a button command and call the command is specified as this:

(Remark: this code is still in development but functional! )

void process_button_press(TouchEventButton button_press_call_back) {
	static uint8_t __buffer[6];
	// Read next 6 bytes 
	if (nexSerial.available() >= 6) {
		for (auto i = 0; i < 6; i++) {
			__buffer[i] = nexSerial.read();
		}
		if (0xFF == __buffer[3] && 0xFF == __buffer[4] && 0xFF == __buffer[5]) {
			// Page, button ID, button pressed state
			button_press_call_back(__buffer[0], __buffer[1], __buffer[2]);
		}
	}
}
void display_loop(TouchEventButton callBack) {
	while (nexSerial.available() > 0) {
		delay(10);
		const uint8_t c = nexSerial.read();
                // Listen to button press and release commands
		if (c == NEX_RET_EVENT_TOUCH_HEAD)	{
			process_button_press(callBack);
		}
	}
}
 

 Note the test on ending 3x255 byte values.


The idea of the code is to have a very responsive Thor robot controller - Nextion HMI display with minimal communication overhead.

Discussions