首页 > 编程问答 >无法将两个字节从 pi 5 主设备发送到从设备 arduino mega(使用 smbus2 库)

无法将两个字节从 pi 5 主设备发送到从设备 arduino mega(使用 smbus2 库)

时间:2024-07-25 10:40:09浏览次数:8  
标签:python arduino raspberry-pi i2c smbus

因此,我尝试使用 smbus2 库中的 write_byte 函数,并成功使用 Raspberry Pi 5 中的该函数来打开和关闭连接到 Arduino Mega 的 LED。

我的项目涉及 3 RPS平行轴机械手由 3 个步进器控制,我正在通过 Pi 5 使用计算机视觉进行数据采集,计算我希望每个机械手电机达到的必要速度、步数和加速度。对于当前的测试,我只为 3 个电机中的每一个发送一组步数、速度和加速度的样本值。由于步长/速度/加速度的值可能高于 255,我认为我需要向 Arduino 发送两个字节,而不是为通过 i2c 发送的每个值发送一个字节,并且必须使用 write_i2c_block_data function 由于我也无法真正使用串行监视器调试arduino代码,因为考虑到它通过USB电缆直接连接到Pi 5,所以我尝试在程序的不同部分打开LED,发现它没有进入“ receiveEvent ”函数如下面的代码所示。

这里可能有什么问题?我在 Pi 5 端没有收到任何错误,当我运行代码(这是 arduino 代码的初始化部分)时,电机会回家,但电机根本不会响应已发送的 i2c 数据而移动。发送给他们。

RPi 5 上的 Python 代码:

from smbus2 import SMBus
from time import sleep
import struct

addr = 0x8 # bus address
bus = SMBus(1) # indicates /dev/i2c-1

steps = [600, 600, 600]
speeds = [500, 500, 500]
accels = [200, 200, 200]
ByteSteps = [0,0,0]
ByteSpeeds = [0,0,0]
ByteAccels = [0,0,0]

for i in range(0,3):
    ByteSteps[i] = list(struct.pack('>h', steps[i]))
    ByteSpeeds[i] = list(struct.pack('>h', speeds[i]))
    ByteAccels[i] = list(struct.pack('>h', accels[i]))

while True:
    for i in range (0,3):
        bus.write_i2c_block_data(addr, 0, ByteSteps[i])
        sleep(0.001)
        bus.write_i2c_block_data(addr, 0, ByteSpeeds[i])
        sleep(0.001)
        bus.write_i2c_block_data(addr, 0, ByteAccels[i])
        sleep(0.001)
    sleep(2)

这是 Arduino 代码:

#include <Wire.h>
#include <AccelStepper.h>
#include <cvzone.h>

// Define motors config
const int MAX_STEPPERS = 3;
const int STEP_PINS[MAX_STEPPERS] = {3, 6, 9};   // Step pins for motors 1, 2, 3
const int DIR_PINS[MAX_STEPPERS] = {2, 5, 8};    // Direction pins for motors 1, 2, 3

// Create instances of AccelStepper for each motor
AccelStepper steppers[MAX_STEPPERS] = {
  AccelStepper(AccelStepper::DRIVER, STEP_PINS[0], DIR_PINS[0]),
  AccelStepper(AccelStepper::DRIVER, STEP_PINS[1], DIR_PINS[1]),
  AccelStepper(AccelStepper::DRIVER, STEP_PINS[2], DIR_PINS[2])
};

// Array to store received parameters for each motor
volatile long receivedSteps[MAX_STEPPERS] = {1, 0, 0}; // Initialize with 0 steps
volatile long receivedSpeed[MAX_STEPPERS] = {1, 0, 0}; // Initialize with 0 speed
volatile long receivedAcceleration[MAX_STEPPERS] = {1, 0, 0}; // Initialize with 0 acceleration

// Variables for managing serial input and commands
volatile bool runAllowed = false;

// The received integer
volatile int receivedValue = 0;

const int ledPin = 13; 

void setup() {
  // Initialize I2C communication as slave
  Wire.begin(0x8); // Address of the Arduino

  // Setup pin 13 as output and turn LED off at the beginning
  pinMode(ledPin, OUTPUT);
  digitalWrite(ledPin, LOW);

  // Set maximum speed and acceleration for each stepper motor
  for (int i = 0; i < MAX_STEPPERS; i++) {
    steppers[i].setMaxSpeed(100000); // Speed = Steps / second
    steppers[i].setAcceleration(800); // Acceleration = Steps /(second)^2
    steppers[i].disableOutputs(); // Disable outputs initially
    steppers[i].setCurrentPosition(0); // Reset current position to 0
  }
  home();
  // Register function to run when data is received
  Wire.onReceive(receiveEvent);
}

void loop() {
  if (runAllowed) {
    runMotors();
  }
  delay(100);
}

// Function to parse integer from I2C data
int parse_Integer() {
  if (Wire.available() >= 2) { // We expect 2 bytes for the integer
    byte byte1 = Wire.read();
    byte byte2 = Wire.read();
    
    // Combine the two bytes to form the integer
    receivedValue = (byte1 << 8) | byte2;
    return receivedValue;
  }
  return 0;
}

// Function to run when data is received
void receiveEvent(int howMany) {
  digitalWrite(ledPin, '1');
  for (int i = 0; i < MAX_STEPPERS; i++) {
      receivedSteps[i] = parse_Integer();
      receivedSpeed[i] = parse_Integer();
      receivedAcceleration[i] = parse_Integer();
  }
  for (int i = 0; i < MAX_STEPPERS; i++) {
    steppers[i].setAcceleration(receivedAcceleration[i]);
    steppers[i].setMaxSpeed(receivedSpeed[i]);
    steppers[i].move(receivedSteps[i]);
  }
  runAllowed = true;
}

void home() {
  runAllowed = true;
  for (int i = 0; i < MAX_STEPPERS; i++) {
    receivedSteps[i] = 200;
    receivedSpeed[i] = 800;
    receivedAcceleration[i] = 100;
  }
  for (int i = 0; i < MAX_STEPPERS; i++) {
    steppers[i].setAcceleration(receivedAcceleration[i]);
    steppers[i].setMaxSpeed(receivedSpeed[i]);
    steppers[i].move(-1 * receivedSteps[i]);
  }
  runMotors();
  for (int i = 0; i < MAX_STEPPERS; i++) {
    steppers[i].setCurrentPosition(0);
  }
  runAllowed = false;
}

void runMotors() {
  if (runAllowed) {
    while (steppers[0].currentPosition() != -1*receivedSteps[0] && steppers[1].currentPosition() != -1*receivedSteps[1] && steppers[2].currentPosition() != -1*receivedSteps[2]) {
      for (int i = 0; i < MAX_STEPPERS; i++) {
        steppers[i].enableOutputs(); // Enable outputs for all motors
        steppers[i].run(); // Step each motor
      }
      // if (Serial.available() > 0) return;
    }
    runAllowed = false;
  }
  if (!runAllowed) {
    for (int i = 0; i < MAX_STEPPERS; i++) {
      steppers[i].disableOutputs(); // Disable outputs for all motors
    }
  }
}

我看到了你代码中的几个问题,这些问题可能会导致 Arduino 没有进入 receiveEvent 函数的问题,因此你的电机没有按照预期移动。让我们分解一下:

Python 端(Raspberry Pi)

  1. 重复的寄存器地址: 你正在使用 bus.write_i2c_block_data(addr, 0, data) 将数据发送到 Arduino。第二个参数 0 代表 Arduino 上的 I2C 寄存器地址。你正在为步长、速度和加速度使用相同的地址 ( 0 ),这会导致数据被覆盖。你应该为每个参数使用唯一的寄存器地址(例如,步长为 0,速度为 1,加速度为 2)。

  2. 不必要的数据转换: struct.pack(">h", value) 方法返回一个字节数组,但你又使用 list(...) 将其转换为列表。 write_i2c_block_data 函数可以直接使用字节数组,因此这种转换是不必要的。

这是更正后的 Python 代码:

from smbus2 import SMBus
from time import sleep
import struct

addr = 0x8 # bus address
bus = SMBus(1) # indicates /dev/i2c-1

steps = [600, 600, 600]
speeds = [500, 500, 500]
accels = [200, 200, 200]

while True:
    for i in range(3):
        bus.write_i2c_block_data(addr, 0, struct.pack(">h", steps[i]))
        sleep(0.001)
        bus.write_i2c_block_data(addr, 1, struct.pack(">h", speeds[i]))
        sleep(0.001)
        bus.write_i2c_block_data(addr, 2, struct.pack(">h", accels[i]))
        sleep(0.001)
    sleep(2)

Arduino 端

  1. 数据接收逻辑: 你的 receiveEvent 函数假设它将在每次调用时接收到所有三个电机的数据。但是,Python 代码一次只为一个电机发送数据。这会导致数据解释不正确。你应该修改 receiveEvent 函数来处理每个接收到的数据块,并跟踪已经接收到哪些数据。

  2. parse_Integer 函数: 你正在 parse_Integer 函数中读取两个字节,这很好,但你并没有跟踪已经读取了多少个字节或为哪个电机读取了数据。

以下是更新后的 Arduino 代码,它解决了这些问题:

#include <Wire.h>
#include <AccelStepper.h>
#include <cvzone.h>

// ... (电机配置与之前相同) ...

// 用于存储每个电机接收到的参数的数组
volatile long receivedSteps[MAX_STEPPERS] = {1, 0, 0}; // 初始化为 0 步
volatile long receivedSpeed[MAX_STEPPERS] = {1, 0, 0}; // 初始化为 0 速度
volatile long receivedAcceleration[MAX_STEPPERS] = {1, 0, 0}; // 初始化为 0 加速度

// 用于跟踪接收到的数据的变量
volatile byte currentMotorIndex = 0;
volatile byte dataReceivedCount = 0;

// ... (其他变量与之前相同) ...

void setup() {
  // ... (初始化与之前相同) ...
  // 注册当接收到数据时要运行的函数
  Wire.onReceive(receiveEvent);
}

void loop() {
  // ... (与之前相同) ...
}

// 当接收到数据时要运行的函数
void receiveEvent(int howMany) {
  digitalWrite(ledPin, HIGH); // 打开 LED 以指示数据接收

  while (Wire.available()) {
    byte receivedByte = Wire.read();

    if (dataReceivedCount == 0) {
      // 接收到的第一个字节 - 电机索引
      currentMotorIndex = receivedByte;
      dataReceivedCount++;
    } else if (dataReceivedCount == 1) {
      // 接收到的第二个字节 - 数据高字节
      receivedSteps[currentMotorIndex] = receivedByte << 8;
      dataReceivedCount++;
    } else if (dataReceivedCount == 2) {
      // 接收到的第三个字节 - 数据低字节
      receivedSteps[currentMotorIndex] |= receivedByte;
      dataReceivedCount = 0; // 重置计数以接收下一个数据

      // 检查是否收到了所有电机的数据
      if (currentMotorIndex == MAX_STEPPERS - 1) {
        // 处理接收到的数据并运行电机
        for (int i = 0; i < MAX_STEPPERS; i++) {
          steppers[i].setAcceleration(receivedAcceleration[i]);
          steppers[i].setMaxSpeed(receivedSpeed[i]);
          steppers[i].move(receivedSteps[i]);
        }
        runAllowed = true;
      }
    }
  }
}

// ... (其他函数与之前相同) ...

在这个更新后的代码中, receiveEvent 函数现在跟踪接收到的数据量以及它属于哪个电机。一旦收到了所有三个电机的数据,它就会更新电机参数并启用电机运行。

通过这些更改,你的 Python 代码和 Arduino 代码应该能够正确地通信并控制步进电机。

标签:python,arduino,raspberry-pi,i2c,smbus
From: 78780445

相关文章

  • 在 VSCode 中激活 conda env 时,“which python”和“sys.path”给出不同的输出
    当我激活condaenv时,选择相应的解释器并在VScode中启动Python乍一看一切似乎都很好:(My_env)name@my_computer:~/Bureau/My_env/Code/current_dir$/home/name/anaconda3/envs/My_env/bin/python-mIPython--no-autoindentPython3.12.4|packagedb......
  • Python课程设计项目期末大作业(含免费源代码)
    选题代码下载地址:https://download.csdn.net/download/s44359487yad/89572689选题程序名称:口红色号识别器选题:基于图像处理、人脸识别和Flask构建的图片口红色号识别及商品推荐系统功能:根据上传的图片自动化图像处理后分析脸部特征,并判断其嘴部妆容状态,依托现......
  • python webbrowser.open 不使用默认浏览器
    对你们来说这是一个好奇的家伙..在我的python程序中webbrowser.open('etc..')打开MicrosoftEdge现在奇怪的是,我在与opensChrome(我的默认值)稍有不同的文件夹中还有另一个python程序关于发生了什么的任何想法吗?!!(我知道有人问过类似的问题,但......
  • 如何在 Mac 上运行 Python 文件来读取 txt 文件并将其写入外部硬盘?
    我目前有一个充满了我想阅读的epub的文件夹,一个我已经阅读过并想再次阅读的epub的文件夹,以及一个相应的文件,其中每个文件都有epub文件的名称。问题是,这些文件夹仅位于我的外部硬盘上。我想要做的是让我的脚本解析这些文件夹中的epub列表,并在我的下载文件夹中创建最新的副......
  • 深入探索:使用Python进行网站数据加载逻辑分析与请求
    作为一名资深的Python程序员,我经常需要从网站中提取数据以供分析或进一步处理。这项任务涉及到对网站数据加载逻辑的深入分析,以及使用Python进行高效的网络请求。在本文中,我将分享如何分析网站的数据加载方式,并使用Python的requests库来模拟浏览器行为,获取所需的数据。网站......
  • 如何将 Python 列表添加到 Excel 中已有值的列的末尾?
    我目前正在尝试编写一个程序,将值附加到列表中,然后将这些值添加到Excel数据表中的列中。每次运行该程序时,我都希望在同一列的末尾添加更多值。所以我不确定如何解决这个问题,而且我在网上找到的其他答案也没有取得多大成功。以下是使用openpyxl库在Python中将......
  • 如何学习Python:糙快猛的大数据之路(学习地图)
    在这个AI和大数据主宰的时代,Python无疑是最炙手可热的编程语言之一。无论你是想转行还是提升技能,学习Python都是一个明智之选。但是,该如何开始呢?今天,让我们聊聊"糙快猛"的Python学习之道。什么是"糙快猛"学习法?"糙快猛"学习法,顾名思义,就是:糙:不追求完美,允许存......
  • Python 中 __get__ 方法的内部原理
    我正在摆弄描述符,结果碰壁了。我以为我可以像使用任何其他方法一样直接调用它,但显然,它似乎不一致或者我遗漏了一些东西。假设我有一个用作描述符的坐标类:|||还有一个Point类,它有2个坐标属性:classCoordinate:def__set_name__(self,owner,name):self._na......
  • 使用带有私钥的云前端生成签名 URL 的问题..使用 Python 3.7 为带有空格的 S3 对象生
    我在使用Python3.7为S3对象生成签名URL时遇到问题。具体来说,键中带有空格的对象的URL会导致“访问被拒绝”错误,而没有空格的对象的URL通常工作正常。但是,并非所有不带空格的对象都能正常工作,带空格的对象始终会失败。fromdatetimeimportdatetime,timedeltaimpo......
  • 有没有更好的方法来在存储库中的一组 python 程序之间共享公共代码
    当我想要快速、轻松地做许多不同的事情时,我会选择Python-即我总是会得到许多Python“程序”-例如一组脚本-或者如果我正在玩一些东西,一堆测试程序等-即始终是许多不同程序的松散集合。但是,我会分享某些内容。例如,如果我正在使用AI-我可能有30个左右完全不相......