STM32 and Raspberry Pi (host computer) interactively control the robotic arm


、The
usual robotic arm is composed of multiple steering gears. I use a (uncommon) five-degree-of-freedom robotic arm on a certain treasure. Although merchants call it six degrees of freedom.

Here, the 6 PWM output channels of STM32F407VGT6 are used to control the movement of the 6 servos. The Raspberry Pi (host computer) communicates with STM32 through the USB to TTL module.

PWM servo control principle

The standard PWM servo has three control lines: power, ground and signal lines.
Small steering gear
Most of the 180° steering gears on the market require a PWM wave period of 20ms, the high level receiving time is usually 0.5 ~ 2.5ms, and the corresponding steering gear rotation angle is 0 ~ 180°. When using the PWM wave to control the servo, you only need to set the clock cycle to 20ms (50Hz), and change the high level time of the PWM wave by changing the comparison value pulse to control the rotation angle of the servo.

STM32CubeMx main configuration

For STM32, I use STM32CubeIDE + Mx for development. The clock block diagram is the default configuration, as shown in the figure.
STM32 clock block diagram

TIMER

Due to the need to control 6 servos, I chose TIM3 (4 PWM outputs) and TIM9 (2 PWM outputs).
The frequency of the PWM output is determined by the clock APB2. From the clock block diagram, the APB2 frequency here is 16MHz; the formula for calculating the frequency of the PWM wave is:

W = APB2 / (PSC + 1)(ARR + 1)

Among them, PSC is the frequency division coefficient, and ARR is the automatic reload value. Here I set PSE to 39 and ARR to 7999.
Timer configuration
Note that when the Counter Mode is different, the direction of rotation of the servo will be different when the comparison value is the same.

Since the high level time of the PWM wave needs to be controlled within 0.5 ~ 2.5ms, the comparison value (pulse) of each PWM channel must be controlled within 200 ~ 1000; (8000 x 0.5 / 20 = 200) (8000 x 2.5 / 20 = 1000)

When the steering gear rotation angle is 90°, the pulse value should be 600. Here I set the comparison value of each PWM output channel to 600.
PWM channel configuration
Since one of the steering gears in the robotic arm I have on hand is used to control the mechanical claws, it is a 90° steering gear, so when configuring the PWM channel to control the steering gear, the comparison value range can only be 200 ~ 600, and the middle value is 400 The single-chip microcomputer I use is STM32F407VGT6, and the PWM output channels corresponding to TIM3 and TIM9 are PA6, PA7, PB0, PB1 and PE5, PE6 respectively.
You only need to set these IO ports as multiplexing push-pull output and pull-up.
GPIO - TEAM

Serial port configuration

Here I choose USART_2 for serial communication, and its Tx and Rx correspond to PA2 and PA3 respectively.

The configuration of the serial port is shown in the figure. Serial port configuration
The asynchronous communication mode is used here. Note that the baud rate and other parameters must match the upper computer.

Serial GPIO
Both PA2 and PA3 are set to multiplex push-pull output with pull-up.

Interrupt control

Since I only use the serial port to receive interrupts here, NVIC does not need to be configured here; if STM32 has other tasks besides controlling the robotic arm, you may need to configure NVIC.

STM32CubeIDE code implementation

After STM32CubuMx is configured and the project is generated, our main task is to design the communication protocol between the host computer and the microcontroller, and complete the serial port receiving interrupt function.

Communication protocol design

My initial design is to send data once through the serial port to control the angle of a single servo; therefore, the data sent needs to include the number of the servo and the target angle of the servo (or the comparison value converted from the angle).

Here I did not design the communication head and control the speed of the steering gear, because here my serial port is only used to transmit commands to control the steering gear, and I use a small steering gear, its speed is not very fast, which can satisfy me Requirements, no need to control its speed.

The design idea is as follows: the
host computer sends 16-bit data each time (2 uint8_t types, the serial port can only send serial port), the servo number is 0~5, the sent pulse value is (200 ~ 1000)-200, and the servo The number value is multiplied by 1000 plus the pulse value minus 200 to get a uint16_t type value; then it is converted to hexadecimal and sent.

Example: Operate the No. 3 servo, the angle is 45°.

Data processing:
3 x 1000 + (45° / 180°) x 800 = 3200;
3200 is converted to hexadecimal: 0x0C80.

STM32 performs the reverse operation to get the original data.

STM32 code implementation

Since the serial port sends two uint8_t type data, it is necessary to convert the two uint8_t type data into one uint16_t type data before decoding.

When the receiving interrupt of USART2 is turned on, it is set to receive two uint8_t type data into the receiving interrupt to facilitate data processing in the receiving interrupt processing function.

uint8_t pulse[2];
HAL_UART_Receive_IT(&huart2, pulse, sizeof(pulse));

The serial port accepts interrupt function code as follows:



void HAL_UART_RxCpltCallback(UART_HandleTypeDef *huart)
{
    
    
	if(huart->Instance == USART2)
	{
    
    
		uint8_t rec0, rec1;

		// 获取接收到的两个字节的数据
		rec0 = *((huart->pRxBuffPtr) - 2);
		rec1 = *((huart->pRxBuffPtr) - 1);

		uint16_t numPart[2], armControl, arm targetPulse;

		// 通过移位与强制转换得到uint16_t类型数据
		numPart[0] = (uint16_t) rec0;
		numPart[1] = (uint16_t) rec1;
		armControl = ((numPart[0] << 8) | numPart[1]);

		// 逆向解码
		arm = armControl / 1000;  // 舵机编号
		targetPulse = armControl % 1000 + 200;	// 目标比较值

		// 通过switch语句改变指定PWM通道的比较值
		switch(arm)
		{
    
    
			case 1:
				__HAL_TIM_SET_COMPARE(&htim3, TIM_CHANNEL_1, targetPulse);
				break;

			case 2:
				__HAL_TIM_SET_COMPARE(&htim3, TIM_CHANNEL_2, targetPulse);
				break;

			case 3:
				__HAL_TIM_SET_COMPARE(&htim3, TIM_CHANNEL_3, targetPulse);
				break;

			case 4:
				__HAL_TIM_SET_COMPARE(&htim3, TIM_CHANNEL_4, targetPulse);
				break;

			case 5:
				__HAL_TIM_SET_COMPARE(&htim9, TIM_CHANNEL_1, targetPulse);
				break;

			case 6:
				__HAL_TIM_SET_COMPARE(&htim9, TIM_CHANNEL_2, targetPulse);
				break;
		}
	}
}

The PWM channel needs to be enabled before entering the while loop;

  HAL_TIM_PWM_Start(&htim3, TIM_CHANNEL_1);
  HAL_TIM_PWM_Start(&htim3, TIM_CHANNEL_2);
  HAL_TIM_PWM_Start(&htim3, TIM_CHANNEL_3);
  HAL_TIM_PWM_Start(&htim3, TIM_CHANNEL_4);
  HAL_TIM_PWM_Start(&htim9, TIM_CHANNEL_1);
  HAL_TIM_PWM_Start(&htim9, TIM_CHANNEL_2);

And enable the serial port receive interrupt in the USART2_IRQHandler function:

void USART2_IRQHandler(void)
{
    
    
  /* USER CODE BEGIN USART2_IRQn 0 */

  /* USER CODE END USART2_IRQn 0 */
  HAL_UART_IRQHandler(&huart2);
  /* USER CODE BEGIN USART2_IRQn 1 */
  HAL_UART_Receive_IT(&huart2, pulse, sizeof(pulse));
  /* USER CODE END USART2_IRQn 1 */
}

test

In the test, I used the Raspberry Pi with Ubuntu 18.04 installed, and the serial debugging tool was CuteCom; the single-chip microcomputer and the steering gear (robotic arm) were powered by a 5V lithium battery, and two bytes of data were manually sent each time, decimal The conversion to hexadecimal is performed on a scientific calculator. The motion of the robotic arm meets expectations.

After testing, sending 12 bytes of data at the same time, the robotic arm can also operate normally.

It should be noted here that when wiring, the ground wire of the steering gear must share the same ground with the microcontroller.

After that, the code sent by the host computer's serial port can be written into C++ or Python program, and the robot arm can be controlled by the host computer.

Guess you like

Origin blog.csdn.net/weixin_46068920/article/details/108646782