Skip to content

14. Interface and application programming

hero

Steering input -> Motor rotate

Torque sensing by Serial Bus Servo Motor

Research

Thanks to Saheen in the Asian Review, I will study the other “Serial Servo Project” with fast reaction.

Given so many choices of programming languages in the Global Lecture by Neil, my local instructor suggested me some might be useful my Final Project.
I chose “Processing” to experience this week.

Here under is the explanation made by ChatGPT5.5 regarding the difference and the relation between Arduino and Processing by below prompt;

What is the difference between Processing and Arduino?
Would you also explain the relation between them?  

Explanation about the difference and the relation between Arduino and Processing by Chat GPT5.5.

Arduino and Processing have different but complementary roles. Arduino is mainly used to interact with the physical world through sensors, actuators, and microcontroller-based control.  

Processing is mainly used to create visual and interactive programs on a computer. In my Final Project, "Semi-Active Kinetic Seat", Arduino can be used to read sensor values from the steering wheel or navigation system to control motors, while Processing can be used to visualize those values as indication, graphs, and system states.  

The relation between them is especially useful for prototyping. Arduino can send sensor data to Processing through serial communication, and Processing can display that data in real time. Processing can also send commands back to Arduino, making it possible to create a simple control interface or debugging dashboard. For my project, this means I can make steering input, seat response, and driver–passenger motion transfer visible on the computer screen before or during physical testing.  

Installation of Processing

There are so many Processing Tutorials.

Start with the Getting Started.
To begin, download the latest version of Processing.
download Processing

Downloading…
downloading

(following is the explanation about starting the Processing from Processing document)
After the installation is complete, launch Processing by double-clicking the icon. On Windows and Linux, you can find it in the Start menu or on your desktop. On macOS, it should be in the Applications folder.

With any luck, the main Processing window will now be visible. However, if the program didn’t start, or you’re otherwise stuck, visit the troubleshooting page for possible solutions.

Installation of “Processing” by double clicking the installer
Installation01

Installation02

i chose “Typical” for the installation
Installation03

Installation04

Installation05

Installation06

Installation07

Learning about Processing

Open Processing application.
Opening Processing

Initial window of Processing

I proceeded by following the Tutorial.

Coding of circle drawing
This line of code means, “prepare 400 pixels in lateral and 400 pixels in vertical as the window size”, and “draw an ellipse, with the center 200 pixels over from the left and 200 pixels down from the top, with a width and height of 300 pixels.”

Then, click the Run button the (triangle button in the Toolbar), and you will get the following window with the drawing.
Circle was drown

If you change the parameter, you will better understand the meaning of the coding.
parameter change
This line of code means, “prepare 400 pixels in lateral and 400 pixels in vertical as the window size”, and “draw an ellipse, with the center 100 pixels over from the left and 100 pixels down from the top, with a width and height of 200 pixels.”

modified coding

Parameter change from circle to oval
Parameter change
Oval was drawn as follows;
oval was drawn

Mouse drawing coding example
mouse drawing code
This program creates a window that is 480 pixels wide and 120 pixels high, and then starts drawing white circles at the position of the mouse. When a mouse button is pressed, the circle color changes to black. We’ll explain more about the elements of this program in detail later. For now, run the code, move the mouse, and click to see what it does. While the sketch is running, the Run button will change color. You can click the square “stop” icon to halt the sketch.

mouse drawing result

Program making for Steering input via slider controlled by PC keyboard

I made a plan for my individual assignment as follows;

PC keyboard left/right arrow
        ↓
Processing sketch
        ↓ USB Serial
XIAO ESP32-C3 / Arduino IDE code
        ↓ UART / Serial Bus Adapter
STS3215 Serial Bus Servo
        ↓
Physical steering/motor rotation  

The Processing program designing process:

  1. Draw a 300 px steering wheel.
  2. Draw a T-shaped line inside it.
  3. Draw a 300 px slider below it.
  4. Move the slider using left/right arrow keys.
  5. Convert slider position into steering angle from -90° to +90°.
  6. Send that angle to the XIAO ESP32-C3 by USB serial.

The Arduino program designing process:

  1. Receive the steering angle from Processing.
  2. Convert -90° to +90° into STS3215 target position.
  3. Command the STS3215 to rotate accordingly.

With the Chat GPT5.5 support, I started the coding as follows;

Coding for Processing part

I created a Processing-based steering wheel interface to simulate steering input for my Final Project. The interface draws a 300-pixel steering wheel with a T-shaped spoke pattern and a horizontal slider below it. The slider length is the same as the steering wheel diameter. By pressing the left and right arrow keys on the PC, the slider moves from left to right, and its position is mapped to a steering angle from -90 degrees to +90 degrees. The Processing sketch sends the steering angle to the XIAO ESP32-C3 through USB serial communication. The XIAO ESP32-C3 receives the angle value and converts it into a target position command for the STS3215 serial bus servo. In this way, the virtual steering wheel motion on the PC can be connected to the physical motion of a serial bus motor. This prototype is useful for my Spinal Communication project because it allows me to test the relationship between steering input, visual motion, and actuator response before integrating the system into the actual seat mechanism.

Draw a 300 px circle as the graphic diameter of steering wheel in PC display
ellipse(0, 0, wheelDiameter, wheelDiameter);  
Draws a lateral line through the center to draw the horizontal steering spoke
line(-wheelRadius, 0, wheelRadius, 0);
Draws a vertical line from center to bottom to be seen as a T-shaped steering wheel together with the horizontal line
ine(0, 0, 0, wheelRadius);
Draws a slider below the wheel
line(sliderLeft, sliderY, sliderRight, sliderY);
Setting the slider length equal to the wheel diameter
float sliderLength = wheelDiameter;

So the slider travel is also 300 px.

float data type is suggested by Chat GPT because of following reason

float data type used to create a variable that can store a decimal number, such as 300.0, 150.5, or -90.0. In Processing, float means a “floating-point number,” which is a number that can have a decimal point. Processing’s official reference explains that float is a data type for floating-point numbers, for example numbers that have a decimal point.
For example:

float wheelDiameter = 300;  

means:

Create a variable named wheelDiameter.  
This variable can store a decimal number.  
At the beginning, put 300 into it.  

Even though 300 looks like an integer, we use float because later we divide it by 2.0, calculate positions, and rotate graphics. For drawing and motion, float is often more convenient than int.

Here under is the Processing part coded by ChatGPT5.5 with following prompt;

Would make a coding for "Processing" as following function step by step?
1. Draw a circle with 300 pixels width.  

2. Then draw a lateral line in the center of the circle from left to right.  

3. Then draw a vertical line from the center of the circle to the bottom of 
   the circle so that the lines make T-like shape. Together with the circle, 
   whole drawing looks like a steering wheel.  

4. Make a slider switch under the steering wheel in lateral direction so that 
   the steering wheel will rotate in connection with the slider switch. 

5. The moving range of slider switch must be same length as the steering
   lateral size.

6. Slider switch can be controlled by PC left and right arrow keys. 

7. Steering angle should follow the slider switch. If the slider switch is located
   in the center, steering wheel is in the neutral. If the slider switch moves by
   PC arrow key to the left end, the steering wheel rotates 90 degrees to the left 
   side. If the slider switch moves to the right end, the steering wheel rotated 
   90 degrees to the right side.  

8. Make a Code for Arduino IDE so that Serial Bus Motor STS3215 rotates along
   the above steering wheel with XIAO ESP36C3 as the microcomputer.  

It didn’t work at the beginning, so that I decided to proceed step by step.
For the first step I asked to design only the processing part for PC graphic controlled by mouse click not by arrow key in Key board.

Code for Processing part with each code line explanation by Chat-GPT5.5

// --------------------------------------------------
// Processing-only steering wheel test
// This version does not use Serial communication.
// It is only for testing the steering wheel drawing
// and the mouse-controlled slider.
// --------------------------------------------------


// -----------------------------
// Steering wheel size variables
// -----------------------------

float wheelDiameter = 300;        
// Create a decimal-number variable named wheelDiameter.
// It stores the diameter of the steering wheel circle.
// The value is 300 pixels.

float wheelRadius = wheelDiameter / 2.0; 
// Create a variable named wheelRadius.
// It stores half of the wheel diameter.
// 300 / 2.0 = 150.0 pixels.
// This is useful because many drawing positions are based on the radius.


// -----------------------------
// Steering wheel center position
// -----------------------------

float wheelCenterX;               
// Create a variable for the X position of the wheel center.
// The value is not assigned yet.
// It will be assigned inside setup().

float wheelCenterY;               
// Create a variable for the Y position of the wheel center.
// The value is not assigned yet.
// It will be assigned inside setup().


// -----------------------------
// Slider position variables
// -----------------------------

float sliderLength = wheelDiameter; 
// Create a variable for the slider length.
// It is set to the same value as wheelDiameter.
// Therefore, the slider movement range is also 300 pixels.

float sliderLeft;                 
// Create a variable for the left end position of the slider.
// The actual value will be calculated inside setup().

float sliderRight;                
// Create a variable for the right end position of the slider.
// The actual value will be calculated inside setup().

float sliderY;                    
// Create a variable for the vertical position of the slider.
// This is the Y coordinate of the slider rail.

float sliderX;                    
// Create a variable for the current horizontal position of the slider knob.
// This value changes when the mouse drags the knob.


// -----------------------------
// Slider knob and dragging state
// -----------------------------

float knobDiameter = 36;          
// Create a variable for the diameter of the blue slider knob.
// The knob size is 36 pixels.

boolean draggingSlider = false;   
// Create a true/false variable.
// false means the slider is not being dragged.
// true means the mouse is currently dragging the slider.


// -----------------------------
// Steering angle variable
// -----------------------------

float steeringAngleDeg = 0;       
// Create a variable for the steering wheel angle in degrees.
// 0 means neutral.
// -90 means rotated left.
// +90 means rotated right.



void setup() {
  // setup() runs only once when the sketch starts.

  size(700, 600);
  // Create the Processing window.
  // The window width is 700 pixels.
  // The window height is 600 pixels.

  smooth();
  // Make drawn shapes look smoother.
  // This improves the edge quality of circles and lines.

  wheelCenterX = width / 2.0;
  // Set the wheel center X position.
  // width is the width of the window.
  // Since width is 700, width / 2.0 = 350.
  // So the wheel is centered horizontally.

  wheelCenterY = 220;
  // Set the wheel center Y position.
  // The steering wheel center is placed 220 pixels from the top.

  sliderLeft = wheelCenterX - sliderLength / 2.0;
  // Calculate the left end of the slider.
  // wheelCenterX is 350.
  // sliderLength is 300.
  // 350 - 150 = 200.
  // So the left end of the slider is x = 200.

  sliderRight = wheelCenterX + sliderLength / 2.0;
  // Calculate the right end of the slider.
  // 350 + 150 = 500.
  // So the right end of the slider is x = 500.

  sliderY = wheelCenterY + wheelRadius + 90;
  // Calculate the Y position of the slider.
  // wheelCenterY is 220.
  // wheelRadius is 150.
  // 220 + 150 + 90 = 460.
  // So the slider is placed below the steering wheel.

  sliderX = wheelCenterX;
  // Set the initial slider knob position to the center.
  // This means the steering angle starts from neutral.
}



void draw() {
  // draw() runs repeatedly.
  // Processing calls draw() again and again to update the screen.

  background(250);
  // Clear the screen with a light gray background.
  // 250 is close to white.

  updateSteeringAngleFromSlider();
  // Calculate the steering angle from the current slider position.

  drawTitle();
  // Draw the title and instruction text.

  drawSteeringWheel();
  // Draw the circular steering wheel and T-shaped lines.

  drawSlider();
  // Draw the slider rail, knob, and labels.

  drawAngleText();
  // Draw the current steering angle as text.
}



void updateSteeringAngleFromSlider() {
  // This function converts slider position into steering angle.

  steeringAngleDeg = map(sliderX, sliderLeft, sliderRight, -90, 90);
  // map() converts one range into another range.
  //
  // sliderX moves from sliderLeft to sliderRight.
  // That movement is converted into -90 degrees to +90 degrees.
  //
  // If sliderX is at sliderLeft, steeringAngleDeg becomes -90.
  // If sliderX is at center, steeringAngleDeg becomes 0.
  // If sliderX is at sliderRight, steeringAngleDeg becomes +90.
}



void drawTitle() {
  // This function draws the title and instruction text.

  fill(30);
  // Set the text color to dark gray.

  textAlign(CENTER, CENTER);
  // Align text horizontally and vertically at its center.

  textSize(22);
  // Set the title text size to 22 pixels.

  text("Mouse-Controlled Steering Wheel Test", width / 2, 40);
  // Draw the title text.
  // It is placed at the horizontal center of the window.
  // Its Y position is 40 pixels from the top.

  textSize(14);
  // Set the instruction text size to 14 pixels.

  fill(90);
  // Set the instruction text color to medium gray.

  text("Click the blue knob or slider line, then drag left / right", width / 2, 70);
  // Draw the instruction text.
  // It appears below the title.
}



void drawSteeringWheel() {
  // This function draws the steering wheel.

  float angleRad = radians(steeringAngleDeg);
  // Convert the steering angle from degrees to radians.
  // Processing's rotate() function uses radians, not degrees.
  // Therefore, -90 degrees, 0 degrees, +90 degrees must be converted.

  pushMatrix();
  // Save the current coordinate system.
  // This is important because we will move and rotate the coordinate system.
  // After drawing the wheel, we will restore it using popMatrix().

  translate(wheelCenterX, wheelCenterY);
  // Move the origin point from the top-left corner of the window
  // to the center of the steering wheel.
  //
  // After this line, position (0, 0) means the wheel center.

  rotate(angleRad);
  // Rotate the coordinate system.
  // Because the wheel is drawn after this line,
  // the whole wheel rotates together.

  noFill();
  // Do not fill the inside of the circle.
  // Only draw the outline.

  stroke(30);
  // Set the line color to dark gray.

  strokeWeight(5);
  // Set the outer circle line thickness to 5 pixels.

  ellipse(0, 0, wheelDiameter, wheelDiameter);
  // Draw the outer circle of the steering wheel.
  // Since the coordinate origin has moved to the wheel center,
  // ellipse(0, 0, 300, 300) draws a 300-pixel circle around the center.

  strokeWeight(6);
  // Set the spoke line thickness to 6 pixels.

  line(-wheelRadius, 0, wheelRadius, 0);
  // Draw the horizontal line from left to right.
  //
  // Start point:  x = -150, y = 0
  // End point:    x = +150, y = 0
  //
  // This creates the lateral spoke of the steering wheel.

  line(0, 0, 0, wheelRadius);
  // Draw the vertical line from the center to the bottom.
  //
  // Start point: x = 0, y = 0
  // End point:   x = 0, y = +150
  //
  // Together with the horizontal line, this makes a T-like shape.

  fill(30);
  // Set fill color to dark gray for the center hub.

  noStroke();
  // Do not draw an outline for the center hub.

  ellipse(0, 0, 18, 18);
  // Draw a small circle at the center of the steering wheel.
  // This represents the hub.

  popMatrix();
  // Restore the coordinate system to the original state.
  // After this line, drawing coordinates return to the normal window coordinates.
}



void drawSlider() {
  // This function draws the slider.

  stroke(120);
  // Set the slider rail color to gray.

  strokeWeight(6);
  // Set the slider rail thickness to 6 pixels.

  line(sliderLeft, sliderY, sliderRight, sliderY);
  // Draw the horizontal slider rail.
  // It starts at sliderLeft and ends at sliderRight.
  // Its length is 300 pixels, same as the steering wheel diameter.

  stroke(180);
  // Set the center and end mark color to lighter gray.

  strokeWeight(2);
  // Set the mark line thickness to 2 pixels.

  line(wheelCenterX, sliderY - 22, wheelCenterX, sliderY + 22);
  // Draw the center mark of the slider.
  // This shows the neutral position.

  line(sliderLeft, sliderY - 14, sliderLeft, sliderY + 14);
  // Draw the left end mark of the slider.
  // This corresponds to -90 degrees.

  line(sliderRight, sliderY - 14, sliderRight, sliderY + 14);
  // Draw the right end mark of the slider.
  // This corresponds to +90 degrees.

  fill(40, 120, 220);
  // Set the knob fill color to blue.

  stroke(20, 70, 150);
  // Set the knob outline color to darker blue.

  strokeWeight(2);
  // Set the knob outline thickness to 2 pixels.

  ellipse(sliderX, sliderY, knobDiameter, knobDiameter);
  // Draw the slider knob.
  // Its X position is sliderX.
  // Its Y position is sliderY.
  // It moves left and right when dragged by the mouse.

  fill(80);
  // Set label text color to gray.

  textSize(12);
  // Set label text size to 12 pixels.

  textAlign(CENTER, CENTER);
  // Align label text to center.

  text("-90 deg", sliderLeft, sliderY + 38);
  // Draw the left label under the slider.

  text("Neutral", wheelCenterX, sliderY + 38);
  // Draw the center label under the slider.

  text("+90 deg", sliderRight, sliderY + 38);
  // Draw the right label under the slider.
}



void drawAngleText() {
  // This function draws the current steering angle text.

  fill(30);
  // Set text color to dark gray.

  textAlign(CENTER, CENTER);
  // Align text to center.

  textSize(18);
  // Set text size to 18 pixels.

  text("Steering angle: " + nf(steeringAngleDeg, 1, 1) + " deg",
       width / 2,
       sliderY + 85);
  // Draw the steering angle text.
  //
  // nf(steeringAngleDeg, 1, 1) formats the number.
  // It shows the angle with one decimal place.
  //
  // Example:
  // 0.0
  // -45.2
  // 90.0
}



// --------------------------------------------------
// Mouse control
// --------------------------------------------------

void mousePressed() {
  // mousePressed() runs once when the mouse button is pressed.

  float d = dist(mouseX, mouseY, sliderX, sliderY);
  // Calculate the distance between the mouse position and the slider knob center.
  //
  // mouseX and mouseY are the current mouse coordinates.
  // sliderX and sliderY are the slider knob coordinates.
  //
  // If this distance is small, the mouse is near the knob.

  if (d <= knobDiameter / 2.0 + 8) {
    // Check whether the mouse is close enough to the knob.
    // knobDiameter / 2.0 is the knob radius.
    // +8 gives a little extra clickable area.

    draggingSlider = true;
    // Start dragging the slider.
  }

  if (mouseX >= sliderLeft && mouseX <= sliderRight &&
      abs(mouseY - sliderY) <= 25) {
    // Check whether the mouse is near the slider rail.
    //
    // mouseX must be between sliderLeft and sliderRight.
    // mouseY must be close to sliderY.
    //
    // abs(mouseY - sliderY) gives the vertical distance
    // between the mouse and slider rail.

    sliderX = constrain(mouseX, sliderLeft, sliderRight);
    // Move the slider knob to the clicked mouse X position.
    //
    // constrain() prevents sliderX from going outside the slider range.

    draggingSlider = true;
    // Start dragging the slider.
  }
}



void mouseDragged() {
  // mouseDragged() runs repeatedly while the mouse button is held
  // and the mouse is moving.

  if (draggingSlider) {
    // Only move the slider if draggingSlider is true.

    sliderX = constrain(mouseX, sliderLeft, sliderRight);
    // Set sliderX to the mouse X position.
    // constrain() keeps it within the slider range.
  }
}



void mouseReleased() {
  // mouseReleased() runs once when the mouse button is released.

  draggingSlider = false;
  // Stop dragging the slider.
}


Mouse-Controlled Steering Wheel Test interface design version 1.0

Video

Important Concepts in This Code

1. float

float creates a variable that can store decimal numbers. Processing’s official reference says that float is for floating-point numbers, such as numbers with a decimal point.
Example:

float steeringAngleDeg = 0;

This means:

Create a variable named steeringAngleDeg.
It stores the steering angle.
It can store values like -45.5, 0.0, or 89.7.

For my project, float is useful because steering angle and screen positions may not always be exact whole numbers.

2. boolean

boolean draggingSlider = false;

boolean stores only two possible values:

true
false

In this program:

false = the slider is not being dragged
true  = the slider is being dragged

3. setup()

void setup() {
}

setup() runs only once at the beginning. It is used for initial settings such as:

  • window size
  • first positions
  • initial values

4. draw()

void draw() {
}

draw() runs repeatedly. It is used to redraw the screen again and again. In this program, draw() continuously updates:

  • steering wheel angle
  • slider position
  • angle text

5. map()

steeringAngleDeg = map(sliderX, sliderLeft, sliderRight, -90, 90);

This is one of the most important lines. It converts:

slider position

into:

steering angle  

So the relationship becomes:

sliderLeft   → -90 degrees
center       →   0 degrees
sliderRight  → +90 degrees

6. pushMatrix() and popMatrix()

These are used to rotate only the steering wheel.

pushMatrix();
translate(wheelCenterX, wheelCenterY);
rotate(angleRad);
...
popMatrix();

Meaning:

Save coordinate system
Move origin to steering wheel center
Rotate the coordinate system
Draw steering wheel
Restore coordinate system

Without this, rotation could affect other drawings such as the slider and text.

7. translate()

translate(wheelCenterX, wheelCenterY);

This moves the drawing origin. Normally, Processing uses the top-left corner as (0, 0). After translate(), the steering wheel center becomes (0, 0). This makes it easier to draw and rotate the steering wheel.

8. rotate()

rotate(angleRad);

This rotates the drawing coordinate system. Because the steering wheel is drawn after rotate(), the whole steering wheel rotates.

9. constrain()

sliderX = constrain(mouseX, sliderLeft, sliderRight);

This prevents the slider from going outside the rail. It means:

If mouseX is smaller than sliderLeft, use sliderLeft.
If mouseX is larger than sliderRight, use sliderRight.
Otherwise, use mouseX.

In Summary about the Processing Part

In this program:
float variables store sizes, positions, and angles.
setup() prepares the window and initial positions.
draw() updates the screen repeatedly.
mousePressed() starts slider operation.
mouseDragged() moves the slider.
map() converts slider position into steering angle.
rotate() turns the steering wheel.

Code for Processing part without each code line explanation for system implementation

// --------------------------------------------------
// Processing-only steering wheel test
// No Serial communication
// No Arduino connection
// --------------------------------------------------

float wheelDiameter = 300;
float wheelRadius = wheelDiameter / 2.0;

float wheelCenterX;
float wheelCenterY;

float sliderLength = wheelDiameter;
float sliderLeft;
float sliderRight;
float sliderY;
float sliderX;

float knobDiameter = 36;
boolean draggingSlider = false;

float steeringAngleDeg = 0;

void setup() {
  size(700, 600);
  smooth();

  wheelCenterX = width / 2.0;
  wheelCenterY = 220;

  sliderLeft = wheelCenterX - sliderLength / 2.0;
  sliderRight = wheelCenterX + sliderLength / 2.0;
  sliderY = wheelCenterY + wheelRadius + 90;

  sliderX = wheelCenterX;
}

void draw() {
  background(250);

  updateSteeringAngleFromSlider();

  drawTitle();
  drawSteeringWheel();
  drawSlider();
  drawAngleText();
}

void updateSteeringAngleFromSlider() {
  steeringAngleDeg = map(sliderX, sliderLeft, sliderRight, -90, 90);
}

void drawTitle() {
  fill(30);
  textAlign(CENTER, CENTER);
  textSize(22);
  text("Mouse-Controlled Steering Wheel Test", width / 2, 40);

  textSize(14);
  fill(90);
  text("Click the blue knob or slider line, then drag left / right", width / 2, 70);
}

void drawSteeringWheel() {
  float angleRad = radians(steeringAngleDeg);

  pushMatrix();
  translate(wheelCenterX, wheelCenterY);
  rotate(angleRad);

  // Outer circle
  noFill();
  stroke(30);
  strokeWeight(5);
  ellipse(0, 0, wheelDiameter, wheelDiameter);

  // Horizontal line
  strokeWeight(6);
  line(-wheelRadius, 0, wheelRadius, 0);

  // Vertical line from center to bottom
  line(0, 0, 0, wheelRadius);

  // Center hub
  fill(30);
  noStroke();
  ellipse(0, 0, 18, 18);

  popMatrix();
}

void drawSlider() {
  // Slider rail
  stroke(120);
  strokeWeight(6);
  line(sliderLeft, sliderY, sliderRight, sliderY);

  // Center mark
  stroke(180);
  strokeWeight(2);
  line(wheelCenterX, sliderY - 22, wheelCenterX, sliderY + 22);

  // End marks
  line(sliderLeft, sliderY - 14, sliderLeft, sliderY + 14);
  line(sliderRight, sliderY - 14, sliderRight, sliderY + 14);

  // Knob
  fill(40, 120, 220);
  stroke(20, 70, 150);
  strokeWeight(2);
  ellipse(sliderX, sliderY, knobDiameter, knobDiameter);

  // Labels
  fill(80);
  textSize(12);
  textAlign(CENTER, CENTER);
  text("-90 deg", sliderLeft, sliderY + 38);
  text("Neutral", wheelCenterX, sliderY + 38);
  text("+90 deg", sliderRight, sliderY + 38);
}

void drawAngleText() {
  fill(30);
  textAlign(CENTER, CENTER);
  textSize(18);
  text("Steering angle: " + nf(steeringAngleDeg, 1, 1) + " deg", width / 2, sliderY + 85);
}

// --------------------------------------------------
// Mouse control
// --------------------------------------------------

void mousePressed() {
  // If mouse is near the slider knob
  float d = dist(mouseX, mouseY, sliderX, sliderY);

  if (d <= knobDiameter / 2.0 + 8) {
    draggingSlider = true;
  }

  // If mouse is near the slider rail
  if (mouseX >= sliderLeft && mouseX <= sliderRight &&
      abs(mouseY - sliderY) <= 25) {
    sliderX = constrain(mouseX, sliderLeft, sliderRight);
    draggingSlider = true;
  }
}

void mouseDragged() {
  if (draggingSlider) {
    sliderX = constrain(mouseX, sliderLeft, sliderRight);
  }
}

void mouseReleased() {
  draggingSlider = false;
}  


Add Serial Communication coding

Step1

For the next step, I should add following line at the very top of the program.

import processing.serial.*;

Then add following near the top;

Serial port;
boolean serialEnabled = false;

int SERIAL_PORT_INDEX = 0;  // Change this after checking the console
int BAUD_RATE = 115200;

float lastSentAngleDeg = 9999;

Step2

At the end of my existing setup() function, add:

println("Available serial ports:");
println(Serial.list());

// Enable Serial only if a port exists
if (Serial.list().length > 0) {
  try {
    port = new Serial(this, Serial.list()[SERIAL_PORT_INDEX], BAUD_RATE);
    port.clear();
    serialEnabled = true;
    println("Serial connected to: " + Serial.list()[SERIAL_PORT_INDEX]);
  } catch (Exception e) {
    serialEnabled = false;
    println("Serial connection failed. Processing UI will continue without Serial.");
  }
}

With this process, even if Serial fails, the Processing UI should continue working.

Step3

Add following function at the bottom of program

void sendAngleIfChanged() {
  if (!serialEnabled || port == null) {
    return;
  }

  if (abs(steeringAngleDeg - lastSentAngleDeg) > 0.5) {
    String message = "A," + nf(steeringAngleDeg, 1, 2) + "\n";
    port.write(message);

    // Do not print every frame, because too much println can slow Processing.
    // println("Send: " + message.trim());

    lastSentAngleDeg = steeringAngleDeg;
  }
}

Processing made Interface to control Servo Motor

Thanks to Kae’s support, the total coding for “Processing” and ” Arduino” were made.

Processing code for Slider input Serial Bus Servo Motor control

// --------------------------------------------------
// Processing-only steering wheel test
// This version does not use Serial communication.
// It is only for testing the steering wheel drawing
// and the mouse-controlled slider.
// --------------------------------------------------


import processing.serial.*;  //new
Serial myPort;  //new

int tpos=0;  //new

// -----------------------------
// Steering wheel size variables
// -----------------------------

float wheelDiameter = 300;        
// Create a decimal-number variable named wheelDiameter.
// It stores the diameter of the steering wheel circle.
// The value is 300 pixels.

float wheelRadius = wheelDiameter / 2.0; 
// Create a variable named wheelRadius.
// It stores half of the wheel diameter.
// 300 / 2.0 = 150.0 pixels.
// This is useful because many drawing positions are based on the radius.


// -----------------------------
// Steering wheel center position
// -----------------------------

float wheelCenterX;               
// Create a variable for the X position of the wheel center.
// The value is not assigned yet.
// It will be assigned inside setup().

float wheelCenterY;               
// Create a variable for the Y position of the wheel center.
// The value is not assigned yet.
// It will be assigned inside setup().


// -----------------------------
// Slider position variables
// -----------------------------

float sliderLength = wheelDiameter; 
// Create a variable for the slider length.
// It is set to the same value as wheelDiameter.
// Therefore, the slider movement range is also 300 pixels.

float sliderLeft;                 
// Create a variable for the left end position of the slider.
// The actual value will be calculated inside setup().

float sliderRight;                
// Create a variable for the right end position of the slider.
// The actual value will be calculated inside setup().

float sliderY;                    
// Create a variable for the vertical position of the slider.
// This is the Y coordinate of the slider rail.

float sliderX;                    
// Create a variable for the current horizontal position of the slider knob.
// This value changes when the mouse drags the knob.


// -----------------------------
// Slider knob and dragging state
// -----------------------------

float knobDiameter = 36;          
// Create a variable for the diameter of the blue slider knob.
// The knob size is 36 pixels.

boolean draggingSlider = false;   
// Create a true/false variable.
// false means the slider is not being dragged.
// true means the mouse is currently dragging the slider.


// -----------------------------
// Steering angle variable
// -----------------------------

float steeringAngleDeg = 0;   
float pSteeringAngleDeg = 0;   //new

// Create a variable for the steering wheel angle in degrees.
// 0 means neutral.
// -90 means rotated left.
// +90 means rotated right.



void setup() {
  // setup() runs only once when the sketch starts.

  size(700, 600);
  // Create the Processing window.
  // The window width is 700 pixels.
  // The window height is 600 pixels.

  smooth();
  // Make drawn shapes look smoother.
  // This improves the edge quality of circles and lines.

  wheelCenterX = width / 2.0;
  // Set the wheel center X position.
  // width is the width of the window.
  // Since width is 700, width / 2.0 = 350.
  // So the wheel is centered horizontally.

  wheelCenterY = 220;
  // Set the wheel center Y position.
  // The steering wheel center is placed 220 pixels from the top.

  sliderLeft = wheelCenterX - sliderLength / 2.0;
  // Calculate the left end of the slider.
  // wheelCenterX is 350.
  // sliderLength is 300.
  // 350 - 150 = 200.
  // So the left end of the slider is x = 200.

  sliderRight = wheelCenterX + sliderLength / 2.0;
  // Calculate the right end of the slider.
  // 350 + 150 = 500.
  // So the right end of the slider is x = 500.

  sliderY = wheelCenterY + wheelRadius + 90;
  // Calculate the Y position of the slider.
  // wheelCenterY is 220.
  // wheelRadius is 150.
  // 220 + 150 + 90 = 460.
  // So the slider is placed below the steering wheel.

  sliderX = wheelCenterX;
  // Set the initial slider knob position to the center.
  // This means the steering angle starts from neutral.


  println(Serial.list());   //new
  myPort = new Serial(this, Serial.list()[2], 115200); //new

}



void draw() {
  // draw() runs repeatedly.
  // Processing calls draw() again and again to update the screen.

  background(250);
  // Clear the screen with a light gray background.
  // 250 is close to white.



  updateSteeringAngleFromSlider();
  // Calculate the steering angle from the current slider position.

  drawTitle();
  // Draw the title and instruction text.

  drawSteeringWheel();
  // Draw the circular steering wheel and T-shaped lines.

  drawSlider();
  // Draw the slider rail, knob, and labels.

  drawAngleText();
  // Draw the current steering angle as text.

   while (myPort.available() > 0) {
    String s = myPort.readStringUntil('\n');
    if (s != null) {
    //  recv = s;
      println(s);
    }
  }

}



void updateSteeringAngleFromSlider() {
  // This function converts slider position into steering angle.

  steeringAngleDeg = map(sliderX, sliderLeft, sliderRight, -90, 90);  

//new
  if((!draggingSlider) && (steeringAngleDeg != pSteeringAngleDeg)){ 
    int val = int(steeringAngleDeg);
    myPort.write(val + "\n");
    pSteeringAngleDeg = steeringAngleDeg;

    delay(10);
  }


  // map() converts one range into another range.
  //
  // sliderX moves from sliderLeft to sliderRight.
  // That movement is converted into -90 degrees to +90 degrees.
  //
  // If sliderX is at sliderLeft, steeringAngleDeg becomes -90.
  // If sliderX is at center, steeringAngleDeg becomes 0.
  // If sliderX is at sliderRight, steeringAngleDeg becomes +90.
}



void drawTitle() {
  // This function draws the title and instruction text.

  fill(30);
  // Set the text color to dark gray.

  textAlign(CENTER, CENTER);
  // Align text horizontally and vertically at its center.

  textSize(22);
  // Set the title text size to 22 pixels.

  text("Mouse-Controlled Steering Wheel Test", width / 2, 40);
  // Draw the title text.
  // It is placed at the horizontal center of the window.
  // Its Y position is 40 pixels from the top.

  textSize(14);
  // Set the instruction text size to 14 pixels.

  fill(90);
  // Set the instruction text color to medium gray.

  text("Click the blue knob or slider line, then drag left / right", width / 2, 70);
  // Draw the instruction text.
  // It appears below the title.
}



void drawSteeringWheel() {
  // This function draws the steering wheel.

  float angleRad = radians(steeringAngleDeg);
  // Convert the steering angle from degrees to radians.
  // Processing's rotate() function uses radians, not degrees.
  // Therefore, -90 degrees, 0 degrees, +90 degrees must be converted.

  pushMatrix();
  // Save the current coordinate system.
  // This is important because we will move and rotate the coordinate system.
  // After drawing the wheel, we will restore it using popMatrix().

  translate(wheelCenterX, wheelCenterY);
  // Move the origin point from the top-left corner of the window
  // to the center of the steering wheel.
  //
  // After this line, position (0, 0) means the wheel center.

  rotate(angleRad);
  // Rotate the coordinate system.
  // Because the wheel is drawn after this line,
  // the whole wheel rotates together.

  noFill();
  // Do not fill the inside of the circle.
  // Only draw the outline.

  stroke(30);
  // Set the line color to dark gray.

  strokeWeight(5);
  // Set the outer circle line thickness to 5 pixels.

  ellipse(0, 0, wheelDiameter, wheelDiameter);
  // Draw the outer circle of the steering wheel.
  // Since the coordinate origin has moved to the wheel center,
  // ellipse(0, 0, 300, 300) draws a 300-pixel circle around the center.

  strokeWeight(6);
  // Set the spoke line thickness to 6 pixels.

  line(-wheelRadius, 0, wheelRadius, 0);
  // Draw the horizontal line from left to right.
  //
  // Start point:  x = -150, y = 0
  // End point:    x = +150, y = 0
  //
  // This creates the lateral spoke of the steering wheel.

  line(0, 0, 0, wheelRadius);
  // Draw the vertical line from the center to the bottom.
  //
  // Start point: x = 0, y = 0
  // End point:   x = 0, y = +150
  //
  // Together with the horizontal line, this makes a T-like shape.

  fill(30);
  // Set fill color to dark gray for the center hub.

  noStroke();
  // Do not draw an outline for the center hub.

  ellipse(0, 0, 18, 18);
  // Draw a small circle at the center of the steering wheel.
  // This represents the hub.

  popMatrix();
  // Restore the coordinate system to the original state.
  // After this line, drawing coordinates return to the normal window coordinates.
}



void drawSlider() {
  // This function draws the slider.

  stroke(120);
  // Set the slider rail color to gray.

  strokeWeight(6);
  // Set the slider rail thickness to 6 pixels.

  line(sliderLeft, sliderY, sliderRight, sliderY);
  // Draw the horizontal slider rail.
  // It starts at sliderLeft and ends at sliderRight.
  // Its length is 300 pixels, same as the steering wheel diameter.

  stroke(180);
  // Set the center and end mark color to lighter gray.

  strokeWeight(2);
  // Set the mark line thickness to 2 pixels.

  line(wheelCenterX, sliderY - 22, wheelCenterX, sliderY + 22);
  // Draw the center mark of the slider.
  // This shows the neutral position.

  line(sliderLeft, sliderY - 14, sliderLeft, sliderY + 14);
  // Draw the left end mark of the slider.
  // This corresponds to -90 degrees.

  line(sliderRight, sliderY - 14, sliderRight, sliderY + 14);
  // Draw the right end mark of the slider.
  // This corresponds to +90 degrees.

  fill(40, 120, 220);
  // Set the knob fill color to blue.

  stroke(20, 70, 150);
  // Set the knob outline color to darker blue.

  strokeWeight(2);
  // Set the knob outline thickness to 2 pixels.

  ellipse(sliderX, sliderY, knobDiameter, knobDiameter);
  // Draw the slider knob.
  // Its X position is sliderX.
  // Its Y position is sliderY.
  // It moves left and right when dragged by the mouse.

  fill(80);
  // Set label text color to gray.

  textSize(12);
  // Set label text size to 12 pixels.

  textAlign(CENTER, CENTER);
  // Align label text to center.

  text("-90 deg", sliderLeft, sliderY + 38);
  // Draw the left label under the slider.

  text("Neutral", wheelCenterX, sliderY + 38);
  // Draw the center label under the slider.

  text("+90 deg", sliderRight, sliderY + 38);
  // Draw the right label under the slider.
}



void drawAngleText() {
  // This function draws the current steering angle text.

  fill(30);
  // Set text color to dark gray.

  textAlign(CENTER, CENTER);
  // Align text to center.

  textSize(18);
  // Set text size to 18 pixels.

  text("Steering angle: " + nf(steeringAngleDeg, 1, 1) + " deg",
       width / 2,
       sliderY + 85);
  // Draw the steering angle text.
  //
  // nf(steeringAngleDeg, 1, 1) formats the number.
  // It shows the angle with one decimal place.
  //
  // Example:
  // 0.0
  // -45.2
  // 90.0
}



// --------------------------------------------------
// Mouse control
// --------------------------------------------------

void mousePressed() {
  // mousePressed() runs once when the mouse button is pressed.

  float d = dist(mouseX, mouseY, sliderX, sliderY);
  // Calculate the distance between the mouse position and the slider knob center.
  //
  // mouseX and mouseY are the current mouse coordinates.
  // sliderX and sliderY are the slider knob coordinates.
  //
  // If this distance is small, the mouse is near the knob.

  if (d <= knobDiameter / 2.0 + 8) {
    // Check whether the mouse is close enough to the knob.
    // knobDiameter / 2.0 is the knob radius.
    // +8 gives a little extra clickable area.

    draggingSlider = true;
    // Start dragging the slider.
  }

  if (mouseX >= sliderLeft && mouseX <= sliderRight &&
      abs(mouseY - sliderY) <= 25) {
    // Check whether the mouse is near the slider rail.
    //
    // mouseX must be between sliderLeft and sliderRight.
    // mouseY must be close to sliderY.
    //
    // abs(mouseY - sliderY) gives the vertical distance
    // between the mouse and slider rail.

    sliderX = constrain(mouseX, sliderLeft, sliderRight);
    // Move the slider knob to the clicked mouse X position.
    //
    // constrain() prevents sliderX from going outside the slider range.

    draggingSlider = true;
    // Start dragging the slider.
  }
}



void mouseDragged() {
  // mouseDragged() runs repeatedly while the mouse button is held
  // and the mouse is moving.

  if (draggingSlider) {
    // Only move the slider if draggingSlider is true.

    sliderX = constrain(mouseX, sliderLeft, sliderRight);
    // Set sliderX to the mouse X position.
    // constrain() keeps it within the slider range.
  }
}



void mouseReleased() {
  // mouseReleased() runs once when the mouse button is released.

  draggingSlider = false;
  // Stop dragging the slider.
}

Arduino code for Slider input Serial Bus Servo Motor control

#include <SCServo.h>

SMS_STS st;

#define S_RXD 20
#define S_TXD 21

const int iniPos = 2047; //Initial Position

int cPos=0; //current position
int cLoad=0; //current load
int tPos=0;

void setup()
{
  Serial1.begin(1000000, SERIAL_8N1, S_RXD, S_TXD);
  st.pSerial = &Serial1;
  st.WritePosEx(1, iniPos, 3400, 50);  // Set Initial Position
  Serial.begin(115200);
  delay(1500);
}


void loop()
{

  if(Serial.available()){
   // String s = Serial.readString();
   // int val = s.toInt();
    int val=Serial.parseInt();

    tPos = map (val, -90,90, iniPos-2000, iniPos+2000); //
    st.WritePosEx(1, tPos, 3400, 50); // servo(ID1) speed=3400,acc=50,move to position=4095.
    Serial.println(tPos);
    delay(1300);
  }
  rcv_data(1);  // Read Torque value at Servo Motor
  delay(10);

}

void rcv_data(int id){
  if(st.FeedBack(id) !=-1){  // ここで通信してよむ
    cPos = st.ReadPos(-1);  // メモリからよむ
    cLoad = st.ReadLoad(-1);
    Serial.print(cPos);
    Serial.print(" , ");
    Serial.println(cLoad);
  }
   delay(100);

}

Steering input -> Motor rotate

In order to read the Torque, modify the following part in Arduino coding;

  rcv_data(1);  // Read Torque value at Servo Motor
  delay(10);

to

  rcv_data(1);  // Read Torque value at Servo Motor
  delay(1500);

Torque sensing by Serial Bus Servo Motor

Torque at the Servo Motor is measured and read.