Skip to content

Commit b47e6a8

Browse files
committed
refactor
1 parent e38509d commit b47e6a8

File tree

5 files changed

+199
-316
lines changed

5 files changed

+199
-316
lines changed

src/drivers/hiwonder_emm/CMakeLists.txt

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -35,9 +35,8 @@ px4_add_module(
3535
MAIN hiwonder_emm
3636
COMPILE_FLAGS
3737
SRCS
38-
main.cpp
3938
HiwonderEMM.cpp
40-
HiwonderEMM.h
39+
HiwonderEMM.hpp
4140
MODULE_CONFIG
4241
module.yaml
4342
DEPENDS

src/drivers/hiwonder_emm/HiwonderEMM.cpp

Lines changed: 98 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -31,15 +31,12 @@
3131
*
3232
****************************************************************************/
3333

34-
#include <px4_log.h>
35-
#include <px4_defines.h>
36-
#include <cmath>
37-
#include "HiwonderEMM.h"
34+
#include "HiwonderEMM.hpp"
3835

39-
HiwonderEMM::HiwonderEMM(int bus, int addr):
40-
I2C(DRV_MOTOR_DEVTYPE_HIWONDER_EMM, MODULE_NAME, bus, addr, 400000)
36+
HiwonderEMM::HiwonderEMM() :
37+
OutputModuleInterface(MODULE_NAME, px4::wq_configurations::hp_default), I2C(DRV_MOTOR_DEVTYPE_HIWONDER_EMM,
38+
MODULE_NAME, I2CBUS, I2C_ADDR, 400000)
4139
{
42-
4340
}
4441

4542
int HiwonderEMM::init()
@@ -51,27 +48,58 @@ int HiwonderEMM::init()
5148
return ret;
5249
}
5350

54-
const uint8_t cmd[2] = {MOTOR_TYPE_ADDR, MOTOR_TYPE_JGB37_520_12V_110RPM};
55-
ret = transfer(cmd, 2, nullptr, 0);
51+
const uint8_t set_motor_type[2] = {MOTOR_TYPE_ADDR, MOTOR_TYPE_JGB37_520_12V_110RPM};
52+
ret = transfer(set_motor_type, 2, nullptr, 0);
5653

5754
if (ret != PX4_OK) {
5855
PX4_ERR("Failed to set motor type. Error: %d", ret);
5956
return ret;
6057
}
6158

62-
const uint8_t cmd2[2] = {MOTOR_ENCODER_POLARITY_ADDR, 0};
63-
ret = transfer(cmd2, 2, nullptr, 0);
59+
const uint8_t set_motor_polarity[2] = {MOTOR_ENCODER_POLARITY_ADDR, 0};
60+
ret = transfer(set_motor_polarity, 2, nullptr, 0);
6461

6562
if (ret != PX4_OK) {
6663
PX4_ERR("Failed to set encoder polarity. Error: %d", ret);
6764
return ret;
6865
}
6966

70-
PX4_INFO("Hiwonder EMM initialized");
67+
this->ChangeWorkQueue(px4::device_bus_to_wq(this->get_device_id()));
68+
69+
PX4_INFO("Hiwonder EMM running on I2C bus %d address 0x%.2x", this->get_device_bus(), this->get_device_address());
70+
71+
ScheduleNow();
7172

7273
return PX4_OK;
7374
}
7475

76+
bool HiwonderEMM::updateOutputs(uint16_t *outputs, unsigned num_outputs,
77+
unsigned num_control_groups_updated)
78+
{
79+
uint8_t speed_values[4];
80+
81+
for (unsigned i = 0; i < num_outputs && i < CHANNEL_COUNT; i++) {
82+
speed_values[i] = (uint8_t)(outputs[i] - 128);
83+
}
84+
85+
set_motor_speed(speed_values);
86+
87+
return true;
88+
}
89+
90+
void HiwonderEMM::Run()
91+
{
92+
if (should_exit()) {
93+
ScheduleClear();
94+
_mixing_output.unregister();
95+
exit_and_cleanup();
96+
return;
97+
}
98+
99+
_mixing_output.update();
100+
_mixing_output.updateSubscriptions(false);
101+
}
102+
75103
int HiwonderEMM::probe()
76104
{
77105
int ret = I2C::probe();
@@ -126,3 +154,61 @@ int HiwonderEMM::set_motor_speed(const uint8_t speed_values[4])
126154

127155
return ret;
128156
}
157+
158+
int HiwonderEMM::print_usage(const char *reason)
159+
{
160+
if (reason) {
161+
PX4_WARN("%s\n", reason);
162+
}
163+
164+
PRINT_MODULE_DESCRIPTION(
165+
R"DESCR_STR(
166+
### Description
167+
Hiwonder encoder motor module driver for PX4.
168+
)DESCR_STR");
169+
170+
PRINT_MODULE_USAGE_NAME("hiwonder_emm", "driver");
171+
PRINT_MODULE_USAGE_COMMAND_DESCR("start", "Start the task");
172+
PRINT_MODULE_USAGE_DEFAULT_COMMANDS();
173+
174+
return 0;
175+
}
176+
177+
int HiwonderEMM::print_status() {
178+
int ret = ModuleBase::print_status();
179+
PX4_INFO("HiwonderEMM @I2C Bus %d, address 0x%.2x",
180+
this->get_device_bus(),
181+
this->get_device_address());
182+
183+
return ret;
184+
}
185+
186+
int HiwonderEMM::custom_command(int argc, char **argv) {
187+
return PX4_OK;
188+
}
189+
190+
int HiwonderEMM::task_spawn(int argc, char **argv) {
191+
auto *instance = new HiwonderEMM();
192+
193+
if (instance) {
194+
_object.store(instance);
195+
_task_id = task_id_is_work_queue;
196+
197+
if (instance->init() == PX4_OK) {
198+
return PX4_OK;
199+
}
200+
201+
} else {
202+
PX4_ERR("alloc failed");
203+
}
204+
205+
delete instance;
206+
_object.store(nullptr);
207+
_task_id = -1;
208+
209+
return PX4_ERROR;
210+
}
211+
212+
extern "C" __EXPORT int hiwonder_emm_main(int argc, char *argv[]){
213+
return HiwonderEMM::main(argc, argv);
214+
}

src/drivers/hiwonder_emm/HiwonderEMM.h

Lines changed: 0 additions & 68 deletions
This file was deleted.
Lines changed: 100 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,100 @@
1+
/****************************************************************************
2+
*
3+
* Copyright (c) 2025 PX4 Development Team. All rights reserved.
4+
*
5+
* Redistribution and use in source and binary forms, with or without
6+
* modification, are permitted provided that the following conditions
7+
* are met:
8+
*
9+
* 1. Redistributions of source code must retain the above copyright
10+
* notice, this list of conditions and the following disclaimer.
11+
* 2. Redistributions in binary form must reproduce the above copyright
12+
* notice, this list of conditions and the following disclaimer in
13+
* the documentation and/or other materials provided with the
14+
* distribution.
15+
* 3. Neither the name PX4 nor the names of its contributors may be
16+
* used to endorse or promote products derived from this software
17+
* without specific prior written permission.
18+
*
19+
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
20+
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
21+
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
22+
* FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
23+
* COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
24+
* INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
25+
* BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS
26+
* OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
27+
* AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
28+
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
29+
* ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
30+
* POSSIBILITY OF SUCH DAMAGE.
31+
*
32+
****************************************************************************/
33+
34+
/**
35+
* @file HiwonderEMM.hpp
36+
*
37+
* Driver for the Hiwonder 4-channel encoder motor driver over I2C.
38+
*
39+
* Product: https://www.hiwonder.com/products/4-channel-encoder-motor-driver
40+
*
41+
*/
42+
43+
#pragma once
44+
45+
#include <cstdint>
46+
#include <drivers/device/i2c.h>
47+
#include <px4_boardconfig.h>
48+
#include <px4_log.h>
49+
#include <drivers/device/device.h>
50+
#include <lib/mixer_module/mixer_module.hpp>
51+
#include <px4_platform_common/module.h>
52+
#include <lib/perf/perf_counter.h>
53+
#include <drivers/drv_hrt.h>
54+
#include <px4_platform_common/getopt.h>
55+
#include <px4_platform_common/sem.hpp>
56+
#include <px4_defines.h>
57+
58+
static constexpr int I2C_ADDR = 0x34; // I2C address
59+
static constexpr int ADC_BAT_ADDR = 0; // Voltage address
60+
static constexpr int MOTOR_TYPE_ADDR = 0x14; // Set the motor type
61+
static constexpr int MOTOR_ENCODER_POLARITY_ADDR = 21; // Set the encoder direction polarity
62+
static constexpr int MOTOR_FIXED_PWM_ADDR = 31; // Fixed PWM control, open loop
63+
static constexpr int MOTOR_FIXED_SPEED_ADDR = 51; // Fixed speed control, closed loop
64+
static constexpr int MOTOR_ENCODER_TOTAL_ADDR = 60; // Total pulse value of 4 encoder motors
65+
static constexpr int MOTOR_TYPE_WITHOUT_ENCODER = 0; // Motor without encoder
66+
static constexpr int MOTOR_TYPE_TT = 1; // TT encoder motor
67+
static constexpr int MOTOR_TYPE_N20 = 2; // N20 encoder motor
68+
static constexpr int MOTOR_TYPE_JGB37_520_12V_110RPM = 3; // JGB37 encoder motor
69+
static constexpr int BUS_FREQUENCY = 100000; // I2C bus frequency
70+
static constexpr int I2CBUS = 1; // I2C bus number
71+
static constexpr int CHANNEL_COUNT = 4; // Number of output channels
72+
73+
class HiwonderEMM : public ModuleBase<HiwonderEMM>, public OutputModuleInterface, public device::I2C
74+
{
75+
public:
76+
HiwonderEMM();
77+
~HiwonderEMM() override = default;
78+
int init() override;
79+
static int task_spawn(int argc, char *argv[]);
80+
static int custom_command(int argc, char *argv[]);
81+
static int print_usage(const char *reason = nullptr);
82+
bool updateOutputs(uint16_t *outputs, unsigned num_outputs,
83+
unsigned num_control_groups_updated) override;
84+
int print_status() override;
85+
86+
protected:
87+
int probe() override;
88+
89+
private:
90+
MixingOutput _mixing_output {
91+
"EMM",
92+
CHANNEL_COUNT,
93+
*this,
94+
MixingOutput::SchedulingPolicy::Auto,
95+
false
96+
};
97+
void Run() override;
98+
int read_adc(int &adc_value);
99+
int set_motor_speed(const uint8_t speed_values[4]);
100+
};

0 commit comments

Comments
 (0)